Node.js操作MongoDB无法统计orders集合数组quantity总和问题
问题排查:MongoDB聚合统计订单products数组quantity总和失败
问题描述
操作MongoDB的orders集合时,尝试统计近两个月内订单中products数组所有元素的quantity总和,预期结果为[ {_id: 10, total: 6 }, { _id: 11, total: 4 } ],但实际返回[ {_id: 10, total: 0 }, { _id: 11, total: 0 } ]。
错误原因分析
- 字段引用错误:原聚合中
$project里的sales: "$quantity"引用了根文档的quantity字段,但实际quantity嵌套在products数组的每个元素中,根文档不存在该字段,导致求和时取到的值为null,累加后为0。 - 未展开数组:没有对
products数组进行拆分展开,无法单独处理每个元素的quantity值。 - 日期计算逻辑错误:原代码中
date.setMonth()会修改原date对象,导致lastMonth和previousMonth的计算基于同一个被修改的日期,可能出现日期范围不符合预期的情况。 - 筛选条件错误:
req.query.pid是商品ID,但原代码中用products: {$elemMatch: {quantity}}来匹配,实际应该匹配productId字段,变量名和字段名不对应。
修正后的代码
const getMonthlySales = asyncHandler(async (req, res) => { const targetProductId = req.query.pid; const now = new Date(); // 正确计算近两个月的起始日期:当前日期往前推两个月,取当月第一天0点 const previousMonthStart = new Date(now.getFullYear(), now.getMonth() - 2, 1); if (req.user.isAdmin) { try { const sales = await Order.aggregate([ // 匹配近两个月的订单,可选按商品ID筛选 { $match: { createdAt: { $gte: previousMonthStart }, ...(targetProductId && { "products.productId": targetProductId }) } }, // 展开products数组,每个元素成为单独文档 { $unwind: "$products" }, // 提取月份和当前product的quantity { $project: { month: { $month: "$createdAt" }, quantity: "$products.quantity" } }, // 按月份分组求和 { $group: { _id: "$month", total: { $sum: "$quantity" } } }, // 可选:按月份排序 { $sort: { _id: 1 } } ]); console.log(sales); res.status(200).json(sales); } catch (err) { res.status(500).json(err); } } else { res.status(403).json("You are not allowed to see monthly income!"); } });
关键修改说明
- 日期计算:改用
new Date(now.getFullYear(), now.getMonth() - 2, 1)直接生成两个月前的当月第一天,避免修改原日期对象导致的逻辑错误,确保统计范围是近两个月的完整周期。 - 数组展开:添加
$unwind: "$products"步骤,将每个订单的products数组拆分为多个独立文档,这样后续可以单独处理每个商品的quantity。 - 字段修正:在
$project中正确引用$products.quantity,并在筛选条件中用"products.productId": targetProductId匹配商品ID(修正原变量名和字段名不匹配的问题)。 - 分组求和:基于展开后的每个商品的quantity进行累加,确保总和计算正确。
内容的提问来源于stack exchange,提问作者Utku Coşkun
相关产品推荐
相关产品推荐

