订单模型按其关联数量的

时间:2019-06-14 13:44:21

标签: sql ruby-on-rails ruby

我想按库存数量在索引视图中订购一些产品(如果有0,则排在最后;如果大于0,则排在前)。

我有以下型号:产品,变型和库存

产品型号

has_many :stocks,   through: :variants

变体模型

belongs_to :product

库存型号

belongs_to :variant

这就是我找到一种产品的全部库存的方式...

 p = Product.last
 p.stocks.map(&:quantity).sum

现在,如何找到所有产品库存的数量,从最大到最小?

2 个答案:

答案 0 :(得分:4)

如果我正确理解,您正在寻找根据Product数量之和按降序返回的所有Stock。如果是这样,这应该为您工作。

@products = Product.left_joins(variants: :stocks) 
       .group(:id)
       .select(Product.arel_table[Arel.star],
               Stock.arel_table[:quantity].sum.as('total_quantity'))
       .order('total_quantity DESC')

这将导致

SELECT 
  products.*,
  SUM(stocks.quantity) AS total_quantity
FROM 
  products 
  LEFT OUTER JOIN variants ON variants.product_id = products.id
  LEFT OUTER JOIN stocks ON stocks.variant_id = variants.id
GROUP BY 
  products.id
ORDER BY 
  total_quantity DESC

似乎是您想要的。这还将向所有已加载的total_quantity对象添加虚拟属性Product,您可以将其用于显示目的,而无需再次访问数据库,例如

@products.each do |p|
  p.total_quantity # virtual attribute equal to SUM(stocks.quantity)
end

最后一点; ;如果您在代码中实际使用了p.stocks.map(&:quantity).sum,出于效率考虑,可以将其更改为p.stocks.sum(:quantity)。这将执行一个适合于SELECT SUM()返回的ActiveRecord::Relation的{​​{1}}查询,这通常比加载所有p.stocks对象然后生成一个{{1} }的数量,然后将这些数量迭代累加为一个数值。

答案 1 :(得分:0)

如果您只是在视图中执行此操作,而不关心是以ActiveRecord::Relation还是Array结尾,则可以使用Enumerable#sort_by方法。

例如在haml视图中:

- @products.sort_by { |p| p.stocks.sum(:quantity) }.reverse.each do |product|
  Qty: #{product.stocks.sum(:quantity)}

如果要在Product上定义一个计算其数量的方法,如下所示:

def stock_quantity
  stocks.sum(:quantity)
end

您可以清理一下:

- @products.sort_by(&:stock_quantity).reverse.each do |product|
  Qty: #{product.stock_quantity}