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

MongoDB聚合查询问题:packets键求和正常,sms_count求和不准确

MongoDB聚合管道中sms_count求和不准确问题排查

问题背景

需要对MongoDB文档中packets对象的键(转换为整数)和sms_count字段分别求和,样本数据如下:

[
    {
        "_id": "6523af5c4b02ad35149ef816",
        "channel": "Default",
        "date": "2023-10-09T07:00:00.000Z",
        "operator": "test_mobilink78",
        "shortcode": "abc",
        "sms_type": "MT",
        "username": "store365",
        "packets": {
            "1": 5
        },
        "sms_count": 5
    },
    {
        "_id": "650c2b728aad44dd1bc0b6a7",
        "channel": "Default",
        "date": "2023-09-21T11:00:00.000Z",
        "operator": "test_zong78",
        "shortcode": "abc",
        "sms_type": "MT",
        "username": "store365",
        "packets": {
            "14": 2
        },
        "sms_count": 2
    }
]

尝试了以下聚合管道查询,packets键的求和结果正确,但sms_count的求和结果不准确,请求排查:

const pipeline: any = [
    {
        $match: {
            date: {
                $gte: startOfDay,
                $lte: endOfDay,
            },
        },
    },
    {
        $addFields: {
            packetKeys: { $map: { input: { $objectToArray: "$packets" }, as: "el", in: { $toInt: "$$el.k" } } }
        }
    },
    {
        $unwind: "$packetKeys"
    },
    {
        $group: {
            _id: {
                $dateToString: {
                    format: "%Y-%m-%d",
                    date: "$date"
                }
            },
            smsHits: { $sum: '$sms_count' },
            apiHits: { $sum: "$packetKeys" }
        }
    },
    {
        $project: {
            _id: 0,
            date: '$_id',
            smsHits: 1,
            apiHits: 1
        }
    },
    {
        $sort: {
            date: 1
        }
    }
];

问题原因

核心问题出在$unwind阶段:当前样本中每个文档的packets只有一个键,$unwind后每个原始文档仅生成1条新文档,暂时不会暴露问题,但如果某个文档的packets包含多个键,$unwind会把该文档拆分成多条,此时$sum: '$sms_count'会重复计算该文档的sms_count多次,导致求和结果偏大。即使当前数据没问题,这个逻辑也存在隐患,后续数据结构变化后问题会直接显现。

修正方案

去掉$addFields和$unwind步骤,直接在$group阶段处理packets键的求和,避免拆分文档导致sms_count重复累加。

修正后的聚合管道

const pipeline: any = [
    {
        $match: {
            date: {
                $gte: startOfDay,
                $lte: endOfDay,
            },
        },
    },
    {
        $group: {
            _id: {
                $dateToString: {
                    format: "%Y-%m-%d",
                    date: "$date"
                }
            },
            smsHits: { $sum: '$sms_count' },
            apiHits: {
                $sum: {
                    $sum: {
                        $map: {
                            input: { $objectToArray: "$packets" },
                            as: "el",
                            in: { $toInt: "$$el.k" }
                        }
                    }
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            date: '$_id',
            smsHits: 1,
            apiHits: 1
        }
    },
    {
        $sort: {
            date: 1
        }
    }
];

逻辑说明

  1. 移除$addFields和$unwind,避免文档被拆分,保证sms_count每个文档只被计算一次
  2. 在apiHits的求和逻辑中:
    • 先用$objectToArray把packets对象转为键值对数组
    • 再用$map将每个键转换为整数
    • 内层$sum计算单个文档中所有packets键的和
    • 外层$sum对分组内所有文档的结果累加
  3. smsHits直接对每个文档的sms_count累加,结果准确

验证结果

用修正后的管道处理样本数据:

  • 2023-10-09:smsHits=5,apiHits=1
  • 2023-09-21:smsHits=2,apiHits=14
    完全符合预期。

内容的提问来源于stack exchange,提问作者Muhammad Omer Hussain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:20:34