【问题标题】:Order model by its association quantity's按关联数量订购模型
【发布时间】:2019-06-14 13:44:21
【问题描述】:

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

我有模型:产品、变体和库存

产品型号

has_many :stocks,   through: :variants

变体模型

belongs_to :product

现货型号

belongs_to :variant

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

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

现在,我怎样才能找到所有产品的库存数量以及从最大到最小的数量?

【问题讨论】:

    标签: sql ruby-on-rails ruby


    【解决方案1】:

    如果我理解正确,您正在寻找所有 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
    

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

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

    最后一点;如果您在代码中实际使用p.stocks.map(&:quantity).sum,出于效率原因,您可以将其更改为p.stocks.sum(:quantity)。这将执行与p.stocks 返回的ActiveRecord::Relation 相匹配的SELECT SUM() 查询,这通常比加载所有Stock 对象,然后生成Array 的数量要好得多,然后迭代累加说数量转化为数值。

    【讨论】:

    • 非常感谢您的帮助我有一个错误ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "stocks.id" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: ... t0_r17, "products"."discounted_price" AS t0_r18, "stocks"."...
    【解决方案2】:

    如果您只是在视图中执行此操作并且不在乎最终是 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}
    

    【讨论】:

    • 这将执行 N*2 + 1 个查询(可能不太理想)。 sum 是一种查询方法,您为@products 中的每个Product 调用它两次
    • 是的。在我的示例中我没有这样做,但可以在 stock_quantity 方法中记住它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多