【问题标题】:Rails 3 Query: How to get most viewed products/articles/whatever?Rails 3 查询:如何获得浏览次数最多的产品/文章/什么?
【发布时间】:2011-04-26 21:01:03
【问题描述】:

我一直想知道如何查询和获取不适合模型的结果。与使用 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 和名称)以及它的查看次数。显然是按观看次数 desc 排序的。

这是我想要得到的 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 方式”思考,也许我错过了一些明显的东西。

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

谢谢

【问题讨论】:

    标签: activerecord arel ruby-on-rails-3


    【解决方案1】:

    您可以使用 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 是一种非常聪明的方式来处理创建可以重用的复杂查询,而不管数据库类型如何。

    【讨论】:

      【解决方案2】:

      在 Product 类的类方法中:

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

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

      【讨论】:

      • 很棒的解决方案。我进行了一些更改以获取哈希数组而不是数组数组。谢谢!
      • 很高兴我能帮上忙!我使用的代码返回哈希值,但为了简洁起见。 :-)
      • 我唯一不喜欢的是使用 IN 子句,而不是内部连接。
      【解决方案3】:

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

      Product.connection.select_rows(sql)
      

      这会给你一个数组数组。如果你想要一个哈希数组,你可以使用select_all

      【讨论】:

      • 模型可以修改,但它似乎是一个常规的“跟踪”表。一个 products 表和一个 product_views(或 hits)表。此外,这种查询(获取浏览次数最多的产品/文章/任何内容)非常受欢迎,我觉得奇怪的是没有简单的方法。
      【解决方案4】:

      试试这个:

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

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

      希望这会有所帮助!

      【讨论】:

      • 我不需要特定产品的计数,我需要按视图排序的产品列表。这无济于事,除非我遍历每个产品并获得计数,这当然不是一个可行的解决方案。
      猜你喜欢
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 1970-01-01
      • 2020-07-07
      相关资源
      最近更新 更多