Complex filtering based on a many-to-many relationship
In my application, Annotations
are considered "accepted" if either:
- They have been explicitly marked "accepted" (i.e., t开发者_JS百科heir state == 'accepted')
- They were last updated by a user who has the "editor" role
My question is how to find all accepted explanations with a single DB query. Basically I'm looking for the database-driven version of
Annotation.all.select do |a|
a.last_updated_by.roles.map(&:name).include?('editor') or a.state == 'accepted'
end
My first attempt was
Annotation.all(:joins => {:last_updated_by => :roles}, :conditions => ['roles.name = ? or annotations.state = ?', 'editor', 'accepted'])
But this returns a bunch of duplicate records (adding a .uniq
makes it work though)
Changing :joins
to :include
works, but this makes the query way too slow
Are the results of your first attempt just wrong or do they only need an ".uniq"? Have you tried
:include => {:last_updated_by => [:roles]}
instead of the join?
or making two queries
@ids = Editor.all(:conditions => ["role = 'editor'"], :select => ["id"]).map{|e|e.id}
Annotation.all(:conditions => ["last_updated_by in (?) or state = ?", @ids.join(","), "accepted"]
is that any faster?
精彩评论