You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 } ]。

错误原因分析

  1. 字段引用错误:原聚合中$project里的sales: "$quantity"引用了根文档的quantity字段,但实际quantity嵌套在products数组的每个元素中,根文档不存在该字段,导致求和时取到的值为null,累加后为0。
  2. 未展开数组:没有对products数组进行拆分展开,无法单独处理每个元素的quantity值。
  3. 日期计算逻辑错误:原代码中date.setMonth()会修改原date对象,导致lastMonth和previousMonth的计算基于同一个被修改的日期,可能出现日期范围不符合预期的情况。
  4. 筛选条件错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:10:33