我正在尝试为我的Rails应用设置搜索。
有2个具有has_and_belongs_to_many关系的模型:
class Post
has_and_belongs_to_many :tags
end
class Tag
has_and_belongs_to_many :post
end
要确认,这是表格:
create_table "posts" do |t|
t.bigint "user_id"
t.string "title"
...
end
create_table "tags" do |t|
t.string "name"
end
create_table "tags_posts", id: false do |t|
t.bigint "post_id", null: false
t.bigint "tag_id", null: false
t.index ["post_id", "tag_id"]
t.index ["tag_id", "post_id"]
end
我要进行AND查询:All POSTS that have TAGS 1, 2, AND 3
。
我得到的最接近的是这个简单的查询,但是它返回OR
而不是AND
-所有具有这3个标记之一的帖子。Post.includes(:tags).where(tags: { id: [1, 2, 3] })
。
如何获得这样的查询,可以在其中轻松地将N个标记ID添加到ActiveRecord查询中,并将其作为AND
查询。
奖金问题-有什么方法可以在返回帖子的地方添加参数,而帖子上至少存在M个标签。所以ALL POSTS that have AT LEAST 2 TAGS of 1, 2, AND 3
?
我发现了这个:https://stackoverflow.com/a/7994175/659820
翻译:
Post.find_by_sql("
SELECT p.* FROM posts p,
post_tags pt1,
post_tags pt2,
tags t1,
tags t2
WHERE
p.id = pt1.post_id
AND t1.id = 4
AND t1.id = pt1.post_tag_id
AND p.id = pt2.post_id
AND t2.id = 11
AND t2.id = pt2.post_tag_id
")
tag_ids = [1, 2, 3] # You can use tag name instead of id
Post.joins(:tags).where(tags: { id: tag_ids }).group(:id).having("count(*) = ?", tag_ids.size)
UPDATE这应该起作用:
class Post < ApplicationRecord def self.tagged_with(post_tags, m = nil) m ||= post_tags.size Post.joins(:tags).where(tags: { id: post_tags }).group(:id).having("count(*) >= ?", m) end end tag_ids = [1, 2, 3] Post.tagged_with(tag_ids) #=> Returns posts which has all tags. Post.tagged_with(tag_ids, 2) #=> Returns posts which has at least two of given tags.