gpt4 book ai didi

ruby-on-rails - has_many 与 `limit` 的关联获取所有记录而不是提供的限制

转载 作者:太空宇宙 更新时间:2023-11-03 16:42:26 25 4
gpt4 key购买 nike

我有一个聊天模型:

class Chat < ApplicationRecord
# Associations
has_many :chat_recipients
has_many :recipients, through: :chat_recipients, source: :person
has_many :messages, dependent: :destroy
has_many :latest_5_messages, -> { order(created_at: :desc).limit(5) }, class_name: Message.name
# Associations
end

和一个消息模型:

class Message < ApplicationRecord
# Associations
belongs_to :person
belongs_to :chat
# Associations
end

这两个关联:

has_many :messages, dependent: :destroy
has_many :latest_5_messages, -> { order(created_at: :desc).limit(5) }, class_name: Message.name

指向相同的模型/类。我希望只提取 5 条消息以减少服务器负载。我已经开发 Rails 应用程序 4 年多了,我注意到一些我觉得有些奇怪的东西。当我在 rails console 上运行这个命令时:2.3.1 :080 > chat = current_person.chats.includes(:recipients, :latest_5_messages).find(1)这是输出:

Chat Load (0.8ms)  SELECT  "chats".* FROM "chats" INNER JOIN "chat_recipients" ON "chats"."id" = "chat_recipients"."chat_id" WHERE "chat_recipients"."person_id" = $1 AND "chats"."id" = $2 LIMIT $3  [["person_id", 1], ["id", 1], ["LIMIT", 1]]
ChatRecipient Load (0.4ms) SELECT "chat_recipients".* FROM "chat_recipients" WHERE "chat_recipients"."chat_id" = 1
Person Load (0.7ms) SELECT "people".* FROM "people" WHERE "people"."id" IN (1, 2)
Message Load (1.0ms) SELECT "messages".* FROM "messages" WHERE "messages"."chat_id" = 1 ORDER BY "messages"."created_at" DESC

可以清楚地看到进行了获取所有消息的查询。但我只想获取 5 条记录,对吗?如果无论如何都要获取所有记录,那么对 has_many 关联应用限制有什么意义。但这不是它,现在我运行:chat.latest_5_messages.count这是输出:

2.3.1 :082 > chat.latest_5_messages.count
(0.9ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "messages" WHERE "messages"."chat_id" = $1 LIMIT $2) subquery_for_count [["chat_id", 1], ["LIMIT", 5]]
=> 5

我的意思是发生了什么事?我喜欢 Rails,我绝对喜欢,但我认为在开发了 4 年多之后,我仍然在追赶 ActiveRecord 的底层工作原理。为什么另一个查询?当我执行 chat.latest_5_messages 时,我在 Associations::CollectionProxy 中恰好看到了 5 条记录,但问题是当我在这个集合上循环时,有 80 多次迭代(它获取所有相关记录都违反了所提供的限制 (5))。看一看:

2.3.1 :087 > chat.latest_5_messages.map(&:id)
=> [190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 172, 170, 169, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102]

我必须执行 chat.latest_5_messages.all 以获得我想要的 5 条记录,但代价是另一个数据库查询,这是我想避免的。

很抱歉,如果这个问题对某些人来说听起来很无聊,我可能不知道 ActiveRecord 的某些部分,但如果有人解释一下,我们将不胜感激。

P.S:这只能使用原始 SQL 查询来实现,还是有办法以 Rails 的方式来实现。

最佳答案

听起来您正试图预先加载具有指定限制的关联,ActiveRecord 不支持这种情况。参见 http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Eager+loading+of+associations

特别是:

If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects

这也在很多其他地方进行了讨论,例如Rails 4 Eager load limit subquery , Rails Eager Load and Limit


虽然我无法解释为什么 map 会为您提供所有记录 - 这看起来确实很奇怪。您是否有机会覆盖 ApplicationRecordmap 的定义?升级到最新的 Rails/ActiveRecord 次要版本对它有什么影响吗?

关于ruby-on-rails - has_many 与 `limit` 的关联获取所有记录而不是提供的限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42671844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com