【问题标题】:How to find posts tagged with more than one tag in Rails and Postgresql如何在 Rails 和 Postgresql 中查找带有多个标签的帖子
【发布时间】:2014-09-01 13:17:52
【问题描述】:

我有模型PostTagPostTag。一篇文章通过文章标签有许多标签。我想查找专门标记有多个标签的帖子。

has_many :post_tags
has_many :tags, through: :post_tags

例如,给定这个数据集:

posts table
--------------------
id | title         |
--------------------
1  | Carb overload |
2  | Heart burn    |
3  | Nice n Light  |

tags table
-------------
id | name   |
-------------
1  | tomato |
2  | potato |
3  | basil  |
4  | rice   |

post_tags table
-----------------------
id | post_id | tag_id |
-----------------------
1  | 1       | 1      |
2  | 1       | 2      |
3  | 2       | 1      |
4  | 2       | 3      |
5  | 3       | 1      |

我想查找带有tomatobasil 标记的帖子。这应该只返回“Heart burn”帖子(id 2)。同样,如果我查询带有tomatopotato 标记的帖子,它应该返回“碳水化合物超载”帖子(id 1)。

我尝试了以下方法:

Post.joins(:tags).where(tags: { name: ['basil', 'tomato'] })

SQL

SELECT "posts".* FROM "posts"
INNER JOIN "post_tags" ON "post_tags"."post_id" = "posts"."id"
INNER JOIN "tags" ON "tags"."id" = "post_tags"."tag_id"
WHERE "tags"."name" IN ('basil', 'tomato')

这会返回所有三个帖子,因为它们都共享标签番茄。我也试过这个:

Post.joins(:tags).where(tags: { name 'basil' }).where(tags: { name 'tomato' })

SQL

SELECT "posts".* FROM "posts"
INNER JOIN "post_tags" ON "post_tags"."post_id" = "posts"."id"
INNER JOIN "tags" ON "tags"."id" = "post_tags"."tag_id"
WHERE "tags"."name" = 'basil' AND "tags"."name" = 'tomato'

这不会返回任何记录。

如何查询带有多个标签的帖子?

【问题讨论】:

    标签: ruby-on-rails postgresql activerecord


    【解决方案1】:

    您可能想查看在this answer for applying conditions to multiple rows in a join 中编写此类查询的可能方法。这是使用 1B(子查询方法)在 Rails 中实现查询的一种可能选择...

    PostTag 模型中定义一个查询,它将获取给定Tag 名称的Post ID 值:

    # PostTag.rb
    def self.post_ids_for_tag(tag_name)
      joins(:tag).where(tags: { name: tag_name }).select(:post_id)
    end
    

    使用子查询结构在Post 模型中定义一个查询,该查询将获取给定Tag 名称的Post 记录:

    # Post.rb
    def self.for_tag(tag_name)
      where("id IN (#{PostTag.post_ids_for_tag(tag_name).to_sql})")
    end
    

    然后你可以使用这样的查询:

    Post.for_tag("basil").for_tag("tomato")
    

    【讨论】:

    • 谢谢。这样可行。但我对子查询方法有点犹豫。我发现joining the table twice under an alias works。尽管如何将其纳入活动记录语法是另一回事。
    • 我看到在 Rails 中实现连接别名的唯一方法是在 joins 命令中使用直接 SQL。类似PostTag.joins("INNER JOIN tags AS t1 ON t1.tag_id = post_tags.tag_id").where("t1.name = ?", "basil")
    【解决方案2】:

    使用方法.includes,像这样:

    Item.where(xpto: "test")
    .includes({:orders =>[:suppliers, :agents]}, :manufacturers)
    

    文档发送至.includeshere

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-02
      • 2015-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-02
      相关资源
      最近更新 更多