Rails 3多对多查询条件

我正在尝试在rails 3中做一个简单的Post / Tags关系。一切正常,除非我想查询与几个标签相关的post。 基本上我想做这样的事情:

Post.joins(:tags).where('tags.name ILIKE ?', var) 

但是我不想只使用一个var,而是想使用一个数组。 我试过了 :

 Post.joins(:tags).where('tags.name IN (?)', names_array) 

但不幸的是,它做了一个简单的LIKE(不是ILIKE),并且像OR条件一样,听起来很合乎逻辑。

我还在这篇文章中使用find_by_sql找到了另一个解决方案http://snippets.dzone.com/posts/show/32

但对我来说似乎有点难看。

为了更好地理解这个问题。 我有3个post:PostA PostB PostC

PostA与TagA TagB和TagC标签相关。 PostB与TagA和TagB标签相关。 PostC仅与TagA有关。

如果我查找TagA和TagCpost,我想找到PostA,因为它与两个标签有关。 使用哈希条件返回PostA PostB和PostC。 我想要的是与“至少”所有指定标签相关的post。

所以任何人都有更好的方法来处理这个问题?

谢谢。

我不知道它是否会解决你的问题,但对于复杂的查询,我几乎总是只使用Squeel 。

然后做这样的事情:

 @posts = Post.joins(:tags) .where{tags.name.like_any names_array} .group("post_id") .having("count(post_id) = #{names_array.size}") 

SQL希望看起来像这样

 SELECT "posts".* FROM "posts" INNER JOIN "tags" ON "tags"."post_id" = "posts"."id" WHERE (("tags"."name" LIKE "TagA" OR "tags"."name" LIKE "TagB")) GROUP BY post_id HAVING count(post_id) = 2 

如果我记得squeel非常擅长使用ILIKE而不是LIKE,具体取决于所使用的数据库。 (至少比AR好)

你也可以使用没有发出吱吱声的 AR来做到这一点,但我真的很喜欢像_all这样的_all一些想法和助手


至于一个探索……

假设我搜索了TagsA和B.

这样做可以找到包含这些标签的所有post。

所以你会有类似的东西:

  • PostA TagA
  • PostA TagB
  • PostB TagA
  • PostB TagB
  • PostC TagA

然后,它将使用post_id按联接标记对所有不同的Post结果进行分组。

  • PostA TagA TagB
  • PostB TagA TagB
  • PostC TagA

然后它将通过检查有多少forgien_ids来检查SQL行具有的标签数量。 由于A和B有2个标签,因此您知道它与您输入的所有标签相匹配。

好的,所以我发现无法避免find_by_sql。 这就是我所做的。

 @posts = Post.find_by_sql([ "SELECT * FROM posts p JOIN ( SELECT pt.post_id FROM posts_tags pt JOIN posts p ON p.id = pt.post_id JOIN tags t ON t.id = pt.tag_id WHERE t.label IN (?) GROUP BY pt.post_id HAVING count(pt.post_id) = ? ) ct ON c.id = ct.post_id", names_array, names_array.size]) 

我个人并不完全理解这个查询(见http://www.sergiy.ca/how-to-write-many-to-many-search-queries-in-mysql-and-hibernate/ – #3) 。 特别是它加入选择的部分。 因此,如果任何人都可以解释这个查询是如何工作的那么会很棒。

此外,如果有人知道如何以更“铁路”的方式(比硬编码查询)这样做,我会喜欢它。

希望这有助于一些人。

我遇到了同样的问题 。 squeel docuemtnation表明这是可能的。 在复合条件部分,他列出了三种类似的方法。

特定

 names = ['Ernie%', 'Joe%', 'Mary%'] 

那你可以做

 Person.where('name LIKE ? OR name LIKE ? OR name LIKE ?', *names) 

要么

 Person.where((['name LIKE ?'] * names.size).join(' OR '), *names) 

要么

 Person.where{name.like_any names} 

文档暗示我们可以使用AND而不是OR或like_all而不是like_any。

但是我似乎无法让它为habtm关系工作。 它一直给我一个ActiveRecord实例的undefined method 'call'