![](/img/trans.png)
[英]How to filter elements to be displayed from a has_many association in rails
[英]How to filter based on has_many association?
我有3个模型
项目
class Project < ApplicationRecord
has_many :taggings
has_many :tags, through: :taggings
end
标记
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :project
end
标签
class Tag < ApplicationRecord
has_many :taggings
has_many :projects, through: :taggings
end
简而言之,项目有许多标签彻底的标签。
我想找出所有给定标签的项目。 我的输入是一组tag
ID(例如 [1,3,5])。 我尝试使用Project.joins(:tags).where(tags: {id: [1 ,3, 5]})
但它会找到具有 id 来自[1,3,5]
的标签之一的项目。 我正在寻找具有所有输入标签的项目。 我怎么做?
tags = [1, 3, 5]
projects = Project.joins(:tags)
.where(tags: {id: tags})
.group(:id)
.having('COUNT(tags) = ?', tags.size)
这将返回具有所有三个标签的项目。
您正在寻找“包含”查询:
SELECT p.*
FROM projects p
INNER JOIN taggings t ON p.id = t.project_id
GROUP BY p.id
HAVING array_agg(t.tag_id ORDER BY t.tag_id) @> ARRAY [1, 3, 5];
这将返回具有所有给定标签但不限于它们的所有项目。 即如果一个项目有标签1, 3, 5, 7
,它将被返回。 但不是一个项目
几个条件:
ARRAY [1, 3, 5]
必须排序p.id
(实际上是projects.id
)必须:a) 是主键或 b) 附加一个唯一性约束。这样做的好处是查询很灵活——您可以更改操作以快速更改含义。 比方说,不是“返回一个包含所有这些标签的项目”,你现在可以写“返回一个只有这些标签的项目”。
考虑这个数据集:
projects:
id name
1 guttenberg
2 x
3 aristotle
tags:
id name
1 books
2 teams
3 management
4 library
5 movie
taggings:
id project_id tag_id
1 1 1
2 1 3
3 1 5
4 2 1
5 2 3
6 3 4
7 3 5
如果您要查询1, 3
,您应该得到项目 1 和 2。
一个可以玩的 SQL 小提琴: http : //sqlfiddle.com/#!17/345dd0/9/1
等效的 ActiveRecord:
tag_ids = [1, 5, 3].sort # condition 1
projects =
Project.joins(:taggings) # don't need tags
.group(:id)
.having("array_agg(taggings.tag_id ORDER BY taggings.tag_id) @> ARRAY[?]", tag_ids)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.