[英]how to make a ruby array be a x,y,z in an ActiveRecord prepared statement
[英]How do I query ActiveRecord to return only the first instance of each object where enum = X, Y, Z?
我们的 CMS 有一篇文章 model,它使用枚举来定义文章类型。
enum display_format: {
webpage: 0,
blog: 1,
interactive: 2,
advertisement: 3,
experience: 4,
product_questions: 5
}
在我们的主页上,我显示每个类别中的最新文章,每个当前都作为单独的查询,就像这样。
Article.where(display_format: :webpage).order(:pub_date).first
Article.where(display_format: :blog).order(:pub_date).first
Article.where(display_format: :interactive).order(:pub_date).first
有没有办法在一个查询中返回这三个记录?
我可以使用Article.where(display_format: [:webpage, :blog, :interactive]).order(:pub_date)
然后过滤集合以获取每个类别的第一项,但我希望有一种更有效的方法在 ActiveRecord 中执行此操作。
如果您已按发布日期顺序对其进行排序,则可以使用.limit(n)
其中 n 是您想要获得的最新文章的数量。
您还可以使用 .first( .first(n)
或.last(n)
,具体取决于您获得所有结果的方式,它们将返回n
多篇文章。
scope :most_recent, ->(formats, num) {
from(
<<~SQL
(
SELECT articles.*,
row_number() OVER (
PARTITION BY articles.display_format
ORDER BY articles.updated_at DESC
) AS rn
FROM articles
) articles
SQL
).where(display_format: formats).where("articles.rn <= #{num}")
}
Article.most_recent([:x, :y, :z], 1) # get top 1 each display_format
Article.most_recent([:x, :y, :z], 10) # get top 10 each display_format
请注意,当您的数据库长大并且您关心性能时,您应该考虑table partition
有不同的方法可以实现这一点,这在很大程度上取决于您使用的 RDBMS,是否有索引来覆盖查询、版本等。但是如果您使用的是 Postgres,则可以使用ROW_NUMBER
加上OVER (PARTITION BY...)
:
Article
.from(
Article
.select(
:display_format,
:pub_date,
'ROW_NUMBER() OVER(PARTITION BY articles.display_format ORDER BY articles.pub_date DESC) AS idx'
)
.where(display_format: [0, 1, 2]),
:articles
)
.where(idx: 1)
在这种情况下,使用“原始” SQL 字符串没有问题,如果适当注意绑定您收到的任何值。 如您所见,ActiveRecord 对使用的这些附加功能一无所知,因此没有支持或内置方法来使用它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.