包括与条件的左连接 has_many 关联
Posted
技术标签:
【中文标题】包括与条件的左连接 has_many 关联【英文标题】:Include a left joined has_many association with condition 【发布时间】:2020-06-20 00:45:31 【问题描述】:如果不触发 N+1 查询,我似乎无法执行关联查询。
假设我举办派对。我有很多朋友,每次有朋友参加聚会,他们都会创建一个 Presence。
所以:
Presence.belongs_to :party
Presence.belongs_to :friend
Friend.has_many :presences
Party.has_many :presences
到目前为止一切顺利。
我想获得我每个朋友的列表,知道他们是否在这个聚会上,而不触发 N+1 查询。
我的数据集如下所示:
friends: [
name: "Dave Vlopment", presences: [created_at: "8pm", party_id: 2012],
name: "Brett E. Hardproblem", presences: [nil],
name: "Ann Plosswan-Quarry", presences: [created_at: "10pm", party_id: 2012],
...
]
等等。
当然,我有很多很多朋友,也参加过很多个聚会。 (这当然是一个虚构的例子。)
我愿意:
Friend.all.includes(:presence).map |them| them.parties
# But then, `them.parties` is not filtered to tonight's party.
Friend.all.includes(:presence).map |them| them.parties.where(party_id: pid)
# And there I have an N+1.
我总是可以在 Ruby 层进行过滤:
Friend.all.includes(:presence).map |them| them.parties.select |it| it.party_id = party.id
但这与as_json(includes: )
等一起工作得非常糟糕。我发现这很容易出错,因为我将根据结果进行计算。
而且我举办了很多 派对,你知道吗? (仍然是虚构的)
如果我在第一个查询中的位置,我会丢失左连接:
Friend.all.includes(:presence).where(party: party)
我不知道今晚,布雷特和一帮一直在那里的朋友缺席了。 (不保证这是虚构的体验)
我只会看到在场的朋友。
如果我通过party
,当然我也不会看到谁缺席。
现在我知道有一些方法可以在 SQL 中做到这一点,还有其他方法我们可以围绕一些 Ruby 将其整合在一起。
但是,我正在寻找一种在 Activerecord 中执行此操作的“一流”方法,而无需获得 N+1。
有没有办法只使用 Activerecord 工具来做到这一点?我还没有找到任何东西。
【问题讨论】:
【参考方案1】:我不确定这是否符合您对“一流”方式的期望。
但是你可以使用这种方法来避免 N+1
# fetch all friends
friends = Friend.all
# fetch all presences. grouped by friend_id
grouped_presences = Presence.all.group_by(&:friend_id)
# arrange data
data = []
friends.each do |friend|
json = friend.as_json
json["presences"] = grouped_presences[friend.id].as_json
data << json
end
puts data
它只执行 2 个查询
SELECT `friends`.* FROM `friends`
SELECT `presences`.* FROM `presences`
【讨论】:
这只是有点hacky和手动,但它仍然是一个解决方案,所以即使它不是我正在寻找的,我也会将其视为积极贡献。谢谢!以上是关于包括与条件的左连接 has_many 关联的主要内容,如果未能解决你的问题,请参考以下文章