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 } } ];
逻辑说明
- 移除
$addFields和$unwind,避免文档被拆分,保证sms_count每个文档只被计算一次 - 在
apiHits的求和逻辑中:- 先用
$objectToArray把packets对象转为键值对数组 - 再用
$map将每个键转换为整数 - 内层
$sum计算单个文档中所有packets键的和 - 外层
$sum对分组内所有文档的结果累加
- 先用
smsHits直接对每个文档的sms_count累加,结果准确
验证结果
用修正后的管道处理样本数据:
- 2023-10-09:
smsHits=5,apiHits=1 - 2023-09-21:
smsHits=2,apiHits=14
完全符合预期。
内容的提问来源于stack exchange,提问作者Muhammad Omer Hussain
相关产品推荐
相关产品推荐

