【问题标题】:Count sold products by specific families in orders by date按日期统计订单中特定系列的已售产品
【发布时间】:2018-04-20 09:15:59
【问题描述】:

我正在尝试找出在给定日期范围内按特定家庭的订单计算已售产品的最佳方法。

这些是我的简化模型:

  • Orderplaced_on
  • OrderItemorder_id、product_id、金额
  • Productfamily_id
  • Family

所以,现在给定一些日期,比如d1d2,我需要计算给定Family 中有多少Product 在这些Order 中。

想要的输出应该是这样的:

# all these are products from the same family sold in the last week
[
  {"product_24": 3435},
  {"product_34": 566},
  {"product_83": 422}
  …
]

我知道如何循环所有订单,但我认为应该有更好的方法。

【问题讨论】:

  • 所以你想要每个订单系列的产品数量?例如订单有 product1 family 1 product2 family2 你得到 2 个计数值 1 ?
  • 我会计算某个家庭在某个时间范围内售出了多少产品。它会产生类似 product1 = 123、product2 = 345 等的东西。但是,如上所述,来自一个系列的产品(产品模型作为 family_id 属性)。

标签: ruby-on-rails activerecord


【解决方案1】:

假设您的数据模型和变量应该是这样的:

OrderItem.joins(:order)
         .joins(product: :family)
         .where(orders: {created_at: d1..d2})
         .where(products: {family_id: <YOUR_FAMILY_ID>})
         .group(:product_id)
         .sum(:amount)

这将生成以下sql:

SELECT
    SUM("order_items"."amount") AS sum_amount,
    "order_items"."product_id" AS order_items_product_id
FROM "order_items"
    INNER JOIN "orders" ON "orders"."id" = "order_items"."order_id"
    INNER JOIN "products" ON "products"."id" = "order_items"."product_id" 
    INNER JOIN "families" ON "families"."id" = "products"."family_id" 
WHERE
    ("orders"."created_at" BETWEEN ? AND ?)
        AND "products"."family_id" = ?
GROUP BY "order_items"."product_id"

并返回以下结构:

=> [{product_id => <sum of this product id since d1 until d2 for family_id>}, ...]

另外,我假设您想对每种产品的数量求和。让我知道是否适合您。

【讨论】:

    【解决方案2】:
    class CreateOrders < ActiveRecord::Migration[5.1]
      def change
        create_table :orders do |t|
          t.timestamps
        end
      end
    end
    
    class CreateOrderItems < ActiveRecord::Migration[5.1]
      def change
        create_table :order_items do |t|
          t.integer :order_id, index:true
          t.integer :product_id, index:true
          t.integer :amount
          t.timestamps
        end
      end
    end
    
    class CreateProducts < ActiveRecord::Migration[5.1]
      def change
        create_table :products do |t|
          t.text :name
          t.integer :family_id, index:true
          t.timestamps
        end
      end
    end
    
    class CreateFamilies < ActiveRecord::Migration[5.1]
      def change
        create_table :families do |t|
          t.text :name
          t.timestamps
        end
      end
    end
    
    class Family < ApplicationRecord
      has_many :products
    end
    
    class Order < ApplicationRecord
      has_many :order_items
      has_many :products, through: :order_items
    end
    
    class OrderItem < ApplicationRecord
      belongs_to :order
      belongs_to :product
    end
    
    class Product < ApplicationRecord
      belongs_to :family
      has_many :order_items
    end
    
    irb(main):015:0> Order.joins(:order_items).joins(:products).where("products.family_id":2).where("orders.created_at": [(Time.now).to_date..(Time.now + 1.day).to_date]).count
       (0.6ms)  SELECT COUNT(*) FROM "orders" INNER JOIN "order_items" ON "order_items"."order_id" = "orders"."id" INNER JOIN "order_items" "order_items_orders_join" ON "order_items_orders_join"."order_id" = "orders"."id" INNER JOIN "products" ON "products"."id" = "order_items_orders_join"."product_id" WHERE "products"."family_id" = ? AND ("orders"."created_at" BETWEEN '2018-04-20' AND '2018-04-21')  [["family_id", 2]]
    => 3
    

    【讨论】:

    • 这几乎就是我想要的。只是这计算了#2 系列的每件产品,我正在寻找一组计算。输出类似 [{"'product_2": 345}, {"product_34": 55}, {"product_3": 422}...]。
    • 如果我添加 group 方法以按 order_items.product_id 分组,那么它还会计算来自不同系列的其他产品,这些产品出现在所需系列产品所在的相同订单中.
    【解决方案3】:

    不是完整的答案,因为您已经有两个非常详细的答案 - 但有一些注释

    我会设置范围...因为我们不确定您的数据库是否垂直...另外,请避免任何时间范围问题,确保您在将混乱输入查询之前得到一整天。这些只是示例,没有经过语法检查或推荐的最佳形式

      # ensure we are getting whole of each day
      full_d1 = d1.beginning_of_day
      full_d2 = d2.end_of_day
    
      #  change the order based on whatever you have more of
      scope :orders -> {where(created_at: full_d1..full_d2)}
      scope :family -> {where(product: family_id)}
    
      # use something like - swap order based on db conditions
      Order.orders.family  # ... then add the rest of what they are throwing down or .size / .count
    

    此外,正如 S/O 中其他地方所述,您可以缓存 has_many 关系的计数 - link

    【讨论】:

      猜你喜欢
      • 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
      相关资源
      最近更新 更多