Существует ассоциативный запрос, который я, кажется, не могу выполнить без запуска запроса N + 1.
Предположим, я принимаю Стороны. У меня много Друзей, и каждый раз, когда друг приходит на вечеринку, они создают Присутствие.
И так:
Presence.belongs_to :party
Presence.belongs_to :friend
Friend.has_many :presences
Party.has_many :presences
Пока все хорошо.
I хочу получить список всех моих друзей, зная, присутствуют ли они на этой вечеринке, без запуска запроса 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)
Я понятия не имею, что сегодня вечером, Бретт и другие друзей, которые всегда рядом, отсутствуют. (не гарантируется, что это вымышленный опыт) * 1044 *
Я буду видеть только друзей, которые присутствуют.
И если я от go до party
, ну, конечно, я тоже не увижу, кто отсутствует.
Теперь я знаю, что есть способы сделать это в SQL, и другие способы, которыми мы можем спорить с некоторыми Ruby, чтобы собрать все вместе.
Однако я ищу «первоклассный» способ сделать это в Activerecord, без получения N + 1.
Есть ли способ сделать это, используя только инструменты Activerecord? Я еще ничего не нашел.