有一个关联查询,如果不触发N + 1查询,我似乎无法执行。
假设我主办缔约方。我有很多朋友,每当一个朋友参加聚会时,他们都会创建一个状态。
等等:
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}]},
...
]
以此类推。
我当然有一个 lot 个朋友,并且参加一个 lot 个聚会。 (这当然是一个虚构的例子。)
我会做的:
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)
我不知道今晚布雷特(Brett)和一堆永远在场的朋友不在。 (不保证这是一种虚构的经历)
我只会看到在场的朋友。
如果我经过party
,当然,我也不会看到谁也缺席。
现在,我知道有一些方法可以在SQL中执行此操作,还有其他方法可以纠缠一些Ruby以将其组合在一起。
但是,我正在ActiveRecord中寻找一种“一流”的方法,而又不会获得N + 1。
是否可以仅使用Activerecord工具来执行此操作?我还没有发现任何东西。
答案 0 :(得分:0)
我不确定这是否符合您对“一流”方式的期望。
但是您可以使用这种方法来避免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`