How do you do this in mysql or rails

109 views Asked by At

Say you have a posts table and a tags table, and both are related by a post_tags table.

so

posts has id/subject/body columns

tags has id/name

post_tags has id/post_id/tag_id

in rails terminology, I have a Post Model that has many Tags through AssetTags.

I'm trying to query for a post that has 2 specific tags. so if there is a rails tag and a mysql tag, I want a query that returns a post that only has those two tags.

make sense?

Any way to do this with activerecord (I'm using search logic) or mysql?

4

There are 4 answers

1
sid On BEST ANSWER

This SQL returns the posts that contain both tags.

select 
  p.* 
from 
  posts p
  ,asset_tags atg1
  ,asset_tags atg2
  ,tags t1
  ,tags t2
where
  p.id = atg1.post_id
and t1.id = atg1.tag_id
and t1.tag = 'MySQL' 
and p.id = atg2.post_id
and t2.id = atg2.tag_id
and t2.tag = 'Rails'
;

As for doing it via Active record, an alternative would be to query for each of the tags and then & the resulting arrays to get the intersection of the two.

1
Igbanam On

John Bachir's answer can be modified to...

Post.joins(:asset_tags => :tag)
    .where("tags.name in ('?')", 'foo')
    .where("tags.name in ('?')", 'bar')
2
dispake On

For mysql, sure, you can get the data

 SELECT p.*
   FROM posts p 
   JOIN post_tags pt
     ON p.post_id = pt.post_id
  WHERE pt.tag_id in (tagId1, tagId2)

I have not used Rails ActiveRecord but I imagine it would be something along the lines of

 get('posts');
 join('post_tags','post_id');
 where_in('tag_id', array(tagId1, tagId2);
 execute();
3
John Bachir On

Given these models:

def Post
  has_many :asset_tags
  has_many :tags, :through => :asset_tags
end

def AssetTag
  has_one :post
  has_one :tag
end

def Tag
  has_many :asset_tags
  has_many :posts, :through => :asset_tags
end

You can do this:

Post.joins(:asset_tags => :tag).where(
  "tags.name in ('?', '?')", 'foo', 'bar' )

Now, this actually doesn't do anything with the has_many :through association -- I'm not sure if there's an even slicker api provided that utilizes that.