如果不触发 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 工具来做到这一点?我还没有找到任何东西。