MongoDB如何unwind动态键对象并移除外层_id得到预期输出
MongoDB动态键对象聚合及输出结构调整方案
问题场景
处理包含数字动态键的集合时,需要按动态键分组累加嵌套bar字段的值,同时解决两个核心问题:
- 动态命名的键无法直接执行
$unwind展开操作 - 聚合分组后结果被外层
_id字段包裹,不符合预期输出格式
样例数据
原始集合
[ { "_id": "foo1", "1": {"bar": 6}, "0": {"bar": 11}, "3": {"bar": 8}, "2": {"bar": 0}, "5": {"bar": 8}, "4": {"bar": 19}, "6": {"bar": 8} }, { "_id": "foo2", "1": {"bar": 18}, "0": {"bar": 3}, "3": {"bar": 19}, "2": {"bar": 0}, "5": {"bar": 13}, "4": {"bar": 17}, "7": {"bar": 8}, "6": {"bar": 8}, "8": {"bar": 8} }, { "_id": "foo3", "1": {"bar": 0}, "0": {"bar": 2}, "3": {"bar": 18}, "2": {"bar": 2}, "4": {"bar": 12} } ]
当前错误输出
[ {"_id": {"2": 2}}, {"_id": {"5": 21}}, {"_id": {"4": 48}}, {"_id": {"8": 8}}, {"_id": {"1": 24}}, {"_id": {"0": 16}}, {"_id": {"3": 45}}, {"_id": {"7": 8}}, {"_id": {"6": 16}} ]
预期输出
[ {"2": 2}, {"5": 21}, {"4": 48}, {"8": 8}, {"1": 24}, {"0": 16}, {"3": 45}, {"7": 8}, {"6": 16} ]
实现方案
核心思路是用$objectToArray将动态键对象转为固定结构的k-v数组,解决动态键无法直接操作的问题,最后通过$replaceRoot重构输出结构去掉多余的_id包裹。
完整聚合管道如下:
db.collection.aggregate([ // 将根文档转为k-v数组,排除原始_id字段避免干扰 { $project: { _id: 0, keyValueList: { $objectToArray: "$$ROOT" } } }, // 展开转换后的k-v数组,每个动态键对应单条文档 { $unwind: "$keyValueList" }, // 按动态键分组,累加对应bar字段的总和 { $group: { _id: "$keyValueList.k", sumValue: { $sum: "$keyValueList.v.bar" } } }, // 重构输出根文档,将分组结果转为单键对象,移除外层_id包裹 { $replaceRoot: { newRoot: { $arrayToObject: [[ { k: "$_id", v: "$sumValue" } ]] } } } ])
关键步骤说明
$objectToArray: "$$ROOT":把顶层所有动态字段转换为{k: 字段名, v: 字段值}结构的数组,是MongoDB处理动态键的标准方案,转换后即可正常使用$unwind、$group等常规聚合操作符$unwind:展开k-v数组后,每条文档对应一个原始动态键和它的嵌套值$replaceRoot配合$arrayToObject:把分组得到的键名和累加值重新拼接为单键对象,直接替换根文档后就不会保留_id外层包裹,输出结果和预期完全一致
内容的提问来源于stack exchange,提问作者wowestudy
相关产品推荐
相关产品推荐

