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

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 }
    }
]);

各阶段解释

  1. $match:过滤指定时间范围的文档,减少后续处理的数据量。
  2. 第一次$group:按country和status联合分组,统计每个国家下单个状态的出现次数。
  3. 第二次$group:按country单独分组,把同一国家的所有状态统计结果整理成键值对数组,为转对象做准备。
  4. $addFields:将状态数组转为键值对对象,同时定义所有需要统计的状态默认值为0。
  5. $addFields:合并默认状态对象与实际统计对象,实际统计值会覆盖默认值,缺失状态则保留默认的0。
  6. $project:将当前国家与对应状态统计结果转为键值对结构,形成{ "_bg": {...} }格式的对象。
  7. $group:把所有国家的统计对象合并成一个大对象,匹配预期输出结构。
  8. $project:移除无用的_id字段,只保留最终统计结果。

内容的提问来源于stack exchange,提问作者Valor_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 03:15:51