Несколько соединений с количеством и с ActiveRecord - PullRequest
0 голосов
/ 28 августа 2018

Мое приложение о профилях, которые имеют много желаний, связанных с фильмами:

class Profile < ApplicationRecord
  has_many :wishes, dependent: :destroy
  has_many :movies, through: :wishes
end

class Wish < ApplicationRecord
  belongs_to :profile
  belongs_to :movie
end

class Movie < ApplicationRecord
  has_many :wishes, dependent: :destroy
  has_many :profiles, through: :wishes
end

Я хотел бы вернуть все фильмы, которые все"желательны" по профилям с идентификаторами 1,2 и 3.

Мне удалось получить этот запрос с использованием необработанного SQL (postgres), но я хотел узнать, как это сделать с ActiveRecord.

select movies.id
    from movies
    join wishes on wishes.movie_id = movies.id
    join profiles on wishes.profile_id = profiles.id and profiles.id in (1,2,3)
    group by movies.id
    having count(*) = 3;

(Я полагаюсь на count (*) = 3, потому что у меня есть уникальный индекс, который предотвращает создание желаний с дублированными парами profile_id-movie_id, но я открыт для лучших решений)

На данный момент лучший подход, который я нашел, это:

profiles = Profile.find([1,2,3])
Wish.joins(:profile, :movie).where(profile: profiles).group(:movie_id).count.select { |_,v| v == 3 }

(Также я бы начал запрос AR с Movie.joins, но мне не удалось найти способ: -)

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Поскольку в запросе я хочу получить коллекцию Movies, запрос ActiveRecord должен начинаться с Movie. Чего мне не хватало, так это того, что мы можем указать таблицу в запросе, например where(profiles: {id: profiles_ids}).

Вот запрос, который я искал. (Да, использование count может показаться немного хрупким, но альтернативой был дорогой подзапрос SQL. Кроме того, я думаю, что это безопасно, если вы используете уникальный индекс из нескольких столбцов.)

profiles_ids = [1,2,3]
Movie.joins(:profiles).where(profiles: {id: profiles_ids}).group(:id).having("COUNT(*) = ?", profiles_ids.size)
0 голосов
/ 28 августа 2018

Так как own_to помещает внешний ключ в таблицу пожеланий, вы можете просто запросить его для своих профилей следующим образом:

Wish.where("profile_id IN (?)", [1,2,3]).includes(:movie).all.map{|w| w.movie}

Это должно дать вам массив всех фильмов по этим трем профилям, жаждущих загрузки фильмов.

...