问题
I have the following models:
class Piece < ActiveRecord::Base
has_many :instrument_pieces
has_many :instruments, through: :instrument_pieces
end
class Instrument < ActiveRecord::Base
has_many :pieces, through: :instrument_pieces
has_many :instrument_pieces
end
class InstrumentPiece < ActiveRecord::Base
belongs_to :instrument
belongs_to :piece
end
And I have the following query:
Piece
.joins(:instrument_pieces)
.where(instrument_pieces: { instrument_id: search_params[:instruments] } )
.find_each(batch_size: 20) do |p|
Where search_params[:instruments] is an array. The problem with this query is that it will retrieve all pieces that have any of the instruments, so if search_params[:instruments] = ["1","3"], the query will return pieces with an instrument association of either 1 or 3 or of both. I'd like the query to only return pieces whose instrument associations include both instruments 1 and 3. I've read through the docs, but I'm still not sure how this can be done...
回答1:
It seems like what I wanted was an intersection between the two queries, so what i ended up doing was:
queries = []
query = Piece.joins(:instruments)
search_params[:instruments].each do |instrument|
queries << query.where(instruments: {id: instrument})
end
sql_str = ""
queries.each_with_index do |query, i|
sql_str += "#{query.to_sql}"
sql_str += " INTERSECT " if i != queries.length - 1
end
Piece.find_by_sql(sql_str).each do |p|
Very ugly, but ActiveRecord doesn't support INTERSECT yet. Time to wait for ActiveRecord 5, I suppose.
回答2:
You can use where clause chaining to achieve this. Try:
query = Piece.joins(:instrument_pieces)
search_params[:instruments].each do |instrument|
query = query.where(instrument_pieces: { instrument_id: instrument } )
end
query.find_each(batch_size: 20) do |p|
or another version
query = Piece.joins(:instruments)
search_params[:instruments].each do |instrument|
query = query.where(instrument_id: instrument)
end
query.find_each(batch_size: 20) do |p|
来源:https://stackoverflow.com/questions/33557338/rails-activerecord-intersect-query-with-has-many-association