Question

I'm trying to return records from A where all matching records from B satisfy a condition. At the moment my query returns records from A where there is any record from B that satisfies the condition. Let me put this into a real world scenario.

Post.joins(:categories)
    .where(:categories => { :type => "foo" })

This will return Posts that have a category of type "foo", what I want is Posts whose categories are ALL of type "foo"!

Help appreciated!

Was it helpful?

Solution

Using your db/schema.rb as posted in #rubyonrails on IRC something like:

Incident.select("incidents.id").
joins("INNER JOIN category_incidents ON category_incidents.incident_id = incidents.id").
joins("INNER JOIN category_marks ON category_marks.category_id = category_incidents.category_id").
where(:category_marks => { :user_group_id => current_user.user_group_id }).
group("incidents.id").
having("SUM(CASE WHEN category_marks.inc = 1 THEN 1 ELSE 0 END) = count(category_indicents.incident_id)")

would do the trick.

It joins the category_marks for the current_user and checks if the count of records with .inc = 1 equals the count of all joined records.

Do note that this only fetches incident.id

OTHER TIPS

I would add a select to the end of this query to check if all categories have type foo. I would also simplify that check by adding an instance method to the Category model.

Post.joins(:categories).select{|p| p.categories.all?(&:type_foo?)}

Category Model

 def type_foo?
   type == "foo"
 end

ADDITION: This is a bit "hacky" but you could make it a scope this way.

class Post < ActiveRecord::Base
  scope :category_type_foo, lambda{ 
    post_ids = Post.all.collect{|p| p.id if p.categories.all?(&:type_foo?).compact
    Post.where(id: post_ids) }
end

Have you tried query in the opposite direction? i.e.

Categories.where(type: 'foo').joins(:posts)

I may have misunderstood your question though.

Another alternative is

Post.joins(:classifications).where(type: 'foo')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top