Rails ActiveRecord intersect query with has_many association

半世苍凉 提交于 2019-12-11 13:58:55

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!