我有Forum
和ForumTag
HABTM关系。我还有一个名为@tags
的变量数组。此数组包含一些ForumTags的名称。我希望能够查询并查找具有该数组所有值的所有论坛。我目前有:
@forums = Forum.joines(:forum_tags).where(:forum_tags => {:name => @tags})。includes(:forum_tags).all
但是,这会返回阵列中至少有一个值的所有论坛。
答案 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。