【问题标题】:How to use aggregation to generate yearly sales report?如何使用聚合生成年度销售报告?
【发布时间】:2022-11-12 00:42:37
【问题描述】:

架构:

const orderSchema = mongoose.Schema(
{

  orderStatus: {
         type: String,
         enum: ["pending", "preparing", "completed", "declined"],
         default: "pending",
  },
   products: [
          {
            product: {
              productId: {
                type: mongoose.Schema.Types.ObjectId,
                ref: "Product",
              },
              productName: String,
              productPrice: Number,
              categoryName: String,
            },
            quantity: {
              type: Number,
              required: true,
            }
            
          },
   ],
   totalPrice: { type: Number },
   acceptDeclineTime: {
      type: Date,
      default: Date.now,
   },
}
);

我想要一份年度销售报告,其中包含接受和拒绝的订单数量,以及每个订单的总价。

我试过了:

orderSchema.aggregate(
    [

     {
        $unwind: {
          path: "$products",
        },
      },

     {

     $group: {
          _id: { $year: { date: "$acceptDeclineTime", timezone: "+03:00" } },
              totalCompletedPrice: {
                $sum: {
                  $cond: [{ $eq: ["$orderStatus", "completed"] }, "$totalPrice", 0],
                },
              },
              totalDeclinedPrice: {
                $sum: {
                  $cond: [{ $eq: ["$orderStatus", "declined"] }, "$totalPrice", 0],
                },
              },
              totalItems: {
                $sum: "$products.quantity",
              },
              completedSales: {
                $sum: {
                  $cond: [{ $eq: ["$orderStatus", "completed"] }, "$products.quantity", 0],
                },
              },
              cancelledSales: {
                $sum: {
                  $cond: [{ $eq: ["$orderStatus", "declined"] }, "$products.quantity", 0],
                },
              },
              
            },
          },

]);

但是价格计算是错误的,因为$unwind 阶段重复了产品的总价格,这将在$sum 操作上出现问题。

【问题讨论】:

  • 您可以编写一个聚合管道,它将根据来自 acceptDeclineTime 的年份值对条目进行分组。您可以在 $facet 运算符上查找以将结果分为接受和拒绝。确保您在日期字段上有正确的索引
  • 请检查我上面的问题,因为我已经添加了我要使用的路径
  • 也许代替"$totalPrice" 使用{$multiply: ["$products.productPrice", "$products.quantity"]}
  • @WernfriedDomscheit productPrice 有时可能不包含餐厅设置的增值税和服务费,而 totalPrice 包含

标签: javascript node.js mongodb mongoose


【解决方案1】:

我认为您必须分组两次,类似于:

orderSchema.aggregate([
   { $unwind: { path: "$products" } },
   {
      $group: {
         _id: {
            year: { $year: { date: "$acceptDeclineTime", timezone: "+03:00" } },
            orderStatus: "$orderStatus"
         },
         products: { $push: "$products" },
         totalPrice: { $sum: "$totalPrice" }
      }
   },
   {
      $group: {
         _id: "$_id.year",
         ...
      }
   }
]);

【讨论】:

  • 使用 push 可能会导致文档到达并可能绕过文档的 16MB 阈值
  • 然后使用prices: {$sum: "$products.productPrice"}, quantity: {$sum: "$products.quantity"}
  • 就像我说的,totalPrice 包括我需要使用的产品价格 + 服务费 + 增值税
【解决方案2】:

来自 reddit 的 pugro 建议的简单解决方案是在 $unwind 操作之前将总价格除以 products 数组的大小,然后在重新组合时将其加起来。

$addFields:{
  totalPrice:{$divide:['$totalPrice',{$size:'$products'}]}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    相关资源
    最近更新 更多