查询Activerecord HABTM关系以包含数组的所有元素

时间:2012-02-25 22:52:33

标签: ruby-on-rails ruby ruby-on-rails-3

我有ForumForumTag HABTM关系。我还有一个名为@tags的变量数组。此数组包含一些ForumTags的名称。我希望能够查询并查找具有该数组所有值的所有论坛。我目前有:

  

@forums = Forum.joines(:forum_tags).where(:forum_tags => {:name => @tags})。includes(:forum_tags).all

但是,这会返回阵列中至少有一个值的所有论坛。

2 个答案:

答案 0 :(得分:5)

以下内容要求论坛在@tags数组中包含所有论坛代码。我假设forum不会多次forum_tag {。}}。

@forums = Forum.joins(:forum_tags).where(:forum_tags => {:name => @tags}).group("forums.id").having(['COUNT(*) = ?', @tags.length]).includes(:forum_tags).all

这将产生如下的SQL查询:

@tags = ['foo', 'bar']

SELECT forums.id, forum_tags.id FROM forums
  LEFT OUTER JOIN forum_tags_forums on forum_tags_forums.forum_id = forums.id
  LEFT OUTER JOIN forum_tags ON forum_tags.id = forum_tags_forums.forum_tag_id
  WHERE forum_tags.name IN ('foo', 'bar')
  GROUP BY forums.id
  HAVING COUNT(*) = 2;

这将按照与给定标记匹配的论坛对连接表中的所有行进行分组。如果COUNT函数具有您要查找的标记总数的值(并且没有重复的forum / forum_tag对),则论坛必须包含所有标记

获取剩余标签(评论中提出的问题):

forum_tags = ForumTag.where(:name => @tags)

@forums_with_leftovers = Forum.select("forums.*, GROUP_CONCAT(forum_tags.name) AS leftover_tags").joins(:forum_tags).where(['forums.id IN (?) AND NOT forum_tags.id IN (?)', @forums, forum_tags]).group("forums.id").all

Forum中的每个@forums_with_leftovers对象都会有一个额外的属性leftover_tags,其中包含每个论坛对象中不包含在原始@tags变量中的逗号分隔的标记列表

答案 1 :(得分:1)

@forums = Forum.joins(:forum_tags).where(:forum_tags => {:name => @tags}).group("forums.id").having(['COUNT(*) = ?', @tags.length]).includes(:forum_tags).all

Don Cruickshank 提出的这个解决方案非常棒!它非常适合我。但是,不需要最后的 .includes 和 .all。