如何编写一个命名范围来过滤传入的所有数组,而不仅仅是匹配一个元素(使用 IN)
我有两个模型,项目和类别,它们之间具有多对多关系。项目模型非常简单:
class Project < ActiveRecord::Base
has_and_belongs_to_many :categories
scope :in_categories, lambda { |categories|
joins(:categories).
where("categories.id in (?)", categories.collect(&:to_i))
}
end
:in_categories 范围接受一组类别 ID(作为字符串),因此使用此范围我可以取回属于至少一个传入类别的每个项目。
但我实际上是什么尝试做的是过滤(更好的名称是:has_categories)。我只想获取属于传入的所有类别的项目。因此,如果我传入 ["1", "3", "4"] 我只想获取属于所有类别。
I have two models, Project and Category, which have a many-to-many relationship between them. The Project model is very simple:
class Project < ActiveRecord::Base
has_and_belongs_to_many :categories
scope :in_categories, lambda { |categories|
joins(:categories).
where("categories.id in (?)", categories.collect(&:to_i))
}
end
The :in_categories scope takes an array of Category IDs (as strings), so using this scope I can get back every project that belongs to at least one of the categories passed in.
But what I'm actually trying to do is filter (a better name would be :has_categories). I want to just get the projects that belong to all of the categories passed in. So if I pass in ["1", "3", "4"] I only want to get the projects that belong to all of the categories.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
SQL 有两种常见的解决方案可以完成您所描述的操作。
自连接:
注意我使用语法来比较元组。这相当于:
一般来说,如果有覆盖索引,自连接解决方案具有非常好的性能。也许
Categories.(project_id,id)
是正确的索引,但请使用 EXPLAIN 分析 SQL 来确定。此方法的缺点是,如果您要搜索与四个不同类别匹配的项目,则需要四个联接。五个类别对应五个连接,等等。
Group-by:
如果您使用 MySQL(我假设您是),大多数 GROUP BY 查询都会调用临时表,这会降低性能。
我将把它作为一个练习,让您将这些 SQL 解决方案之一改编为等效的 Rails ActiveRecord API。
There are two common solutions in SQL to do what you're describing.
Self-join:
Note I'm using syntax to compare tuples. This is equivalent to:
In general, the self-join solution has very good performance if you have a covering index. Probably
Categories.(project_id,id)
would be the right index, but analyze the SQL with EXPLAIN to be sure.The disadvantage of this method is that you need four joins if you're searching for projects that match four different categories. Five joins for five categories, etc.
Group-by:
If you're using MySQL (I assume you are), most GROUP BY queries invoke a temp table and this kills performance.
I'll leave it as an exercise for you to adapt one of these SQL solutions to equivalent Rails ActiveRecord API.
看起来在 ActiveRecord 中你会这样做:
It seems like in ActiveRecord you would do it like so: