2016-01-04 4 views
0

У меня возникли проблемы с созданием Active Record Rails 4 с запросом db Postgres, который фильтрует массив идентификаторов через таблицу has_many через join.Rails ActiveRecord join query

Например:

class Example < ActiveRecord::Base 
    has_many :available_options 
    has_many :options, through: :available_options 
end 

class AvailableOptions < ActiveRecord::Base 
    belongs_to :options 
    belongs_to :example 
end 

Example.joins(:options).where(item: true).where(options: {id: [1,2,3]}) 

Это возвращает все примеры, которые имеют 1 или 2 или 3 в качестве опции. Я хотел бы привести примеры, в которых есть ВСЕ опции, и только ВСЕ опции.

Есть ли способ выполнить такой запрос?

Благодаря

ответ

0

Вы должны сделать следующее с вашими моделями

class Example < ActiveRecord::Base 
    has_many :available_options 
    has_many :options, through: :available_options 
end 

class AvailableOption < ActiveRecord::Base 
    belongs_to :option 
    belongs_to :example 
end 

и ваш запрос должен выглядеть следующим образом

Example.joins(:options) 
.where(item: true) 
.where(options: {id: [1,2,3]}) 
.having("count(options.id) = 3") 

Чтобы сделать его более динамичным

option_ids = [1, 2, 3] 
Example.joins(:options) 
.where(item: true) 
.where(options: {id: [1,2,3]}) 
.having("count(options.id) = #{options_ids.size}") 
+1

После использовали для группы фильтров? Отсутствует заявление group_by? –

0
  1. В идеале, мы находим AvailableOption (ы), которые имеют все ID [1, 2, 3]

    option_ids = [1, 2, 3]

    join_sql = AvailableOption.where(option_id: option_ids).group(:example_id).select(:example_id).having("COUNT(*) = ?", option_ids.size).to_sql

выше SQL возвращает все example_id (s), который нам нужен

  1. присоединяется с примером, чтобы получить окончательный результат

    Example.joins("JOIN (#{join_sql}) AS TEMP ON id=TEMP.example_id").where(item: true)

-1

Я думаю, что вы можете попробовать это:

option_ids = [1, 2, 3] 
Example.joins(:options) 
.where(item: true) 
.where(options: {id: option_ids}) 
.group(:id) 
.having("count(options.id) = #{options_ids.size}")