У меня есть таблица самообъединения «многие ко многим», которая называется people
и использует следующую модель:
class Person < ApplicationRecord
has_and_belongs_to_many :children,
class_name: "Person",
join_table: "children_parents",
foreign_key: "parent_id",
association_foreign_key: "child_id",
optional: true
has_and_belongs_to_many :parents,
class_name: "Person",
join_table: "children_parents",
foreign_key: "child_id",
association_foreign_key: "parent_id",
optional: true
end
Если это не очевидно в приведенной выше модели - в дополнение к таблице people
в базе данных, существует также таблица соединения children_parents
с двумя полями индекса внешнего ключа child_id
и parent_id
. Это позволяет нам представлять отношения «многие ко многим» между детьми и родителями.
Я хочу запросить информацию о братьях и сестрах человека, поэтому я добавил следующий метод в модель Person:
def siblings
self.parents.map do |parent|
parent.children.reject { |child| child.id == self.id }
end.flatten.uniq
end
Однако это делает три SQL-запроса:
Person Load (1.0ms) SELECT "people".* FROM "people" INNER JOIN "children_parents" ON "people"."id" = "children_parents"."parent_id" WHERE "children_parents"."child_id" = $1 [["child_id", 3]]
Person Load (0.4ms) SELECT "people".* FROM "people" INNER JOIN "children_parents" ON "people"."id" = "children_parents"."child_id" WHERE "children_parents"."parent_id" = $1 [["parent_id", 1]]
Person Load (0.4ms) SELECT "people".* FROM "people" INNER JOIN "children_parents" ON "people"."id" = "children_parents"."child_id" WHERE "children_parents"."parent_id" = $1 [["parent_id", 2]]
Я знаю, что это можно сделать одним SQL-запросом, например:
SELECT DISTINCT(p.*) FROM people p
INNER JOIN children_parents cp ON p.id = cp.child_id
WHERE cp.parent_id IN ($1, $2)
AND cp.child_id != $3
$1
и $2
- это родительские идентификаторы человека, а $3
- это идентификатор человека.
Есть ли способ сделать этот запрос с помощью ActiveRecord?