Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails: Get all items tagged x AND y AND z

I've got two models: Item and Tag. Both have a name attribute. I want to find items tagged with several tags.

class Item < ActiveRecord::Base
  has_many :tags
  validates_presence_of :name
end

class Tag < ActiveRecord::Base
  belongs_to :item
  validates_presence_of :name
end

Given a list of tag ids, I can easily enough get the list of items tagged with one tag or the other:

# Find the items tagged with one or more of the tags on tag_ids
Item.all(:conditions => ['tags.id in (?)', tag_ids], :joins => :tags)

If tag_ids is {1,4}, then I get all pictures tagged with 1, or 4, or both.

I want to know now how to get the pictures that are tagged with both - 1 AND 4.

I can't even imagine the SQL that is needed here.

like image 281
kikito Avatar asked Jun 15 '10 14:06

kikito


2 Answers

You can solve this by grouping the results and checking the count:

Item.all(
  :conditions => ['tags.id IN (?)', tag_ids], 
  :joins      => :tags, 
  :group      => 'items.id', 
  :having     => ['COUNT(*) >= ?', tag_ids.length]
)
like image 84
elektronaut Avatar answered Sep 19 '22 13:09

elektronaut


Little update : Today, we can use (inspired by elektronaut) :

Item.joins(:tags).where("tags.label in (?)", tags).group('items.id').having("COUNT(*) >= ?", tags.size)

It is not very different, by it works well here.

like image 41
Arthur Avatar answered Sep 19 '22 13:09

Arthur