Rails 3 查询:如何获取浏览次数最多的产品/文章/其他内容?

发布于 2024-11-03 05:38:26 字数 1100 浏览 1 评论 0原文

我一直想知道如何查询并获取不适合模型的结果。与使用 LINQ 并投影到匿名对象中的完成方式类似。

这是一个简单的模式:

# Product.rb
class Product < ActiveRecord::Base
   has_many :product_views

   # attributes: id, name, description, created_at, updated_at
end

# ProductView.rb
class ProductView < ActiveRecord::Base
   belongs_to :product

   # attributes: id, product_id, request_ip, created_at, updated_at
end

基本上我需要获取产品列表(最好只是 id 和名称)以及它的浏览次数。显然是按观看次数降序排列的。

这是我想要得到的 SQL:

select 
    p.id,
    p.name,    
    count(pv.product_id) as views
from 
    product_views pv
inner join
    products p on pv.product_id = p.id
group by
    pv.product_id
order by
    count(product_id) desc

我尝试了以下和类似的操作,但是我正在获取 ProductView 对象,并且我只想获取一个数组或其他内容。

ProductView.includes(:product)
           .group('product_id')
           .select("products.id, products.name, count(product_id)")

使用普通 SQL 或 LINQ 来处理这种事情是微不足道的,但我发现自己在 Rails 中遇到了这种查询问题。也许我没有以著名的“轨道方式”思考,也许我错过了一些明显的东西。

那么如何在 Rails 3 中执行此类查询,特别是这个查询呢?欢迎提出任何改进我这样做的方式的建议。

谢谢

I always wondered how to query and get results that doesn't fit in a model. Similar how it's done using LINQ and projecting into anonymous objects.

So here's the simple schema:

# Product.rb
class Product < ActiveRecord::Base
   has_many :product_views

   # attributes: id, name, description, created_at, updated_at
end

# ProductView.rb
class ProductView < ActiveRecord::Base
   belongs_to :product

   # attributes: id, product_id, request_ip, created_at, updated_at
end

Basically I need to get a list of Products (preferably just id and name) along with the count of views it had. Obviously ordered by view count desc.

This is the SQL I want to get:

select 
    p.id,
    p.name,    
    count(pv.product_id) as views
from 
    product_views pv
inner join
    products p on pv.product_id = p.id
group by
    pv.product_id
order by
    count(product_id) desc

I tried the following and similar, but I'm getting ProductView objects, and I would like to get just an array or whatever.

ProductView.includes(:product)
           .group('product_id')
           .select("products.id, products.name, count(product_id)")

This kind of thing are trivial using plain SQL or LINQ, but I find myself stucked with this kind of queries in Rails. Maybe I'm not thinking in the famous 'rails way', maybe I'm missing something obvious.

So how do you do this kind of queries in Rails 3, and specifically this one? Any suggestions to improve the way I'm doing this are welcome.

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

逆夏时光 2024-11-10 05:38:26

您可以使用 Arel 来完成您想要的操作:

products = Product.arel_table
product_views = ProductView.arel_table

# expanded for readability:
sql = products.join(product_views)
              .on(product_views[:product_id].eq(product[:id]))
              .group(product_views[:product_id])
              .order('views DESC')
              .project(products[:id],
                       products[:name],
                       product_views[:id].count.as('views'))

products_with_views = Product.connection.select_all(sql.to_sql) # or select_rows to just get the values

是的,它很长,但是 Arel 是一种非常智能的方法来处理创建可以重用的复杂查询,无论数据库类型如何。

You can use Arel to do what you're looking for:

products = Product.arel_table
product_views = ProductView.arel_table

# expanded for readability:
sql = products.join(product_views)
              .on(product_views[:product_id].eq(product[:id]))
              .group(product_views[:product_id])
              .order('views DESC')
              .project(products[:id],
                       products[:name],
                       product_views[:id].count.as('views'))

products_with_views = Product.connection.select_all(sql.to_sql) # or select_rows to just get the values

Yes, it is long, but Arel is a very smart way to deal with creating complex queries that can be reused regardless of the database type.

匿名。 2024-11-10 05:38:26

在 Product 类的类方法中:

Product.includes(:product_views).all.map { |p| [p.id, p.name, p.product_views.size] }

然后根据需要对其进行排序。

Within a class method in the Product class:

Product.includes(:product_views).all.map { |p| [p.id, p.name, p.product_views.size] }

Then sort it however you want.

兲鉂ぱ嘚淚 2024-11-10 05:38:26

我不知道是否有办法使用您的模型来做到这一点。我可能会求助于:

Product.connection.select_rows(sql)

这会给你一个数组的数组。如果您希望拥有哈希数组,可以使用 select_all

I don't know if there's a way to do it using your models. I would probably resort to:

Product.connection.select_rows(sql)

Which will give you an array of arrays. You can use select_all if you'd rather have an array of hashes.

二智少女 2024-11-10 05:38:26

试试这个:(

@product = Product.find(#product_id)
@product_views = @product.product_views.count

来源 - http://ar.rubyonrails.org/classes /ActiveRecord/Calculations/ClassMethods.html#M000292

希望这有帮助!

Try this:

@product = Product.find(#product_id)
@product_views = @product.product_views.count

(Source - http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M000292)

Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文