在has_and_belongs_to_many关系上使用AND而不是OR的ActiveRecord查询的倍数

问题描述 投票:1回答:1

我正在尝试为我的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
")
  1. 这是完成此任务的最有效方法吗?
  2. 奖励问题仍未得到解答-为提供的N个标签提供M个匹配项?
activerecord ruby-on-rails-5
1个回答
1
投票
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.
© www.soinside.com 2019 - 2024. All rights reserved.