MongoDB聚合查询:按国家分组统计各状态数量(含0值)
正确的MongoDB聚合查询实现按国家分组统计各状态数量
需求说明
针对MongoDB中的文档,先按country字段分组,再在每个国家分组内统计SENT、CREATED、ERROR、WAITING、CANCELED各状态的数量,无对应状态时显示0。
示例文档
[ { "status": "SENT", "country": "_bg", "createdAt": "<dataTime>" }, { "status": "CREATED", "country": "_de", "createdAt": "<dataTime>" }, { "status": "SENT", "country": "_de", "createdAt": "<dataTime>" }, { "status": "ERROR", "country": "_de", "createdAt": "<dataTime>" }, { "status": "SENT", "country": "_bg", "createdAt": "<dataTime>" } ]
预期输出
[ { "_de": { "SENT": 1, "CREATED": 1, "ERROR": 1, "WAITING": 0, "CANCELED": 0 }, "_bg": { "SENT": 2, "CREATED": 0, "ERROR": 0, "WAITING": 0, "CANCELED": 0 } } ]
当前错误查询代码
const totalPerCounty = await Model.aggregate([ { $match: { createdAt: { $gt: new Date(from), $lt: new Date(to), } }, }, { $group: { _id: {country: '$country'}, status: { $push: { status: "$status", count: "$count" } }, 'count': {$sum: 1} } } ]);
正确聚合查询写法
const totalPerCounty = await Model.aggregate([ // 过滤时间范围内的文档 { $match: { createdAt: { $gt: new Date(from), $lt: new Date(to) } } }, // 按国家+状态分组,统计各状态数量 { $group: { _id: { country: "$country", status: "$status" }, count: { $sum: 1 } } }, // 按国家重新分组,整理状态统计为k-v数组 { $group: { _id: "$_id.country", statusCounts: { $push: { k: "$_id.status", v: "$count" } } } }, // 转状态数组为对象,同时定义所有状态的默认值 { $addFields: { statusObj: { $arrayToObject: "$statusCounts" }, defaultStatus: { SENT: 0, CREATED: 0, ERROR: 0, WAITING: 0, CANCELED: 0 } } }, // 合并默认值与实际统计结果,覆盖已有值 { $addFields: { mergedStatus: { $mergeObjects: ["$defaultStatus", "$statusObj"] } } }, // 整理为国家为键、状态统计为值的结构 { $project: { _id: 0, countryStats: { $arrayToObject: [[{ k: "$_id", v: "$mergedStatus" }]] } } }, // 合并所有国家的统计结果为一个对象 { $group: { _id: null, result: { $mergeObjects: "$countryStats" } } }, // 移除无用字段,保留最终结果 { $project: { _id: 0 } } ]);
各阶段解释
- $match:过滤指定时间范围的文档,减少后续处理的数据量。
- 第一次$group:按
country和status联合分组,统计每个国家下单个状态的出现次数。 - 第二次$group:按
country单独分组,把同一国家的所有状态统计结果整理成键值对数组,为转对象做准备。 - $addFields:将状态数组转为键值对对象,同时定义所有需要统计的状态默认值为0。
- $addFields:合并默认状态对象与实际统计对象,实际统计值会覆盖默认值,缺失状态则保留默认的0。
- $project:将当前国家与对应状态统计结果转为键值对结构,形成
{ "_bg": {...} }格式的对象。 - $group:把所有国家的统计对象合并成一个大对象,匹配预期输出结构。
- $project:移除无用的
_id字段,只保留最终统计结果。
内容的提问来源于stack exchange,提问作者Valor_
相关产品推荐
相关产品推荐

