如何在MongoDB中对嵌套数组使用分组聚合操作?
MongoDB按嵌套数组字段分组并保留原始对象的解决方案
我正尝试使用MongoDB的$group聚合操作,现有一个包含名为children的嵌套数组字段的文档,希望按children的job字段进行分组。尝试用$unwind时,返回的不是单个children对象列表,而是带有不同job的父对象副本。
测试数据
[ { "name": "Peter", "age": 50, "job": "retired", "children": [ { "name": "Alex", "age": 33, "job": "teacher", "children": null }, { "name": "Jenny", "age": 31, "job": "teacher", "children": null }, { "name": "Rob", "age": 28, "job": "scientist", "children": null }, { "name": "Harry", "age": 27, "job": "teacher", "children": null }, { "name": "Tim", "age": 21, "job": "student", "children": null } ] } ]
当前查询语句
db.collection.aggregate([ { $match: { name: "Peter" } }, { $group: { _id: "$children.job", count: { $sum: 1 } } } ])
当前返回结果
[ { "_id": [ "teacher", "teacher", "scientist", "teacher", "student" ], "count": 1 } ]
期望结果
{ "count": { "teacher": 3, "scientist": 1, "student": 1 } }
我想知道能否获取数组的原始对象?因为$unwind返回的只是指定字段不同的父对象副本。
解决方案
1. 生成期望的count键值对结构
要得到你想要的统计结果,需要先拆解嵌套数组,再分组统计,最后转换为键值对格式:
db.collection.aggregate([ { $match: { name: "Peter" } }, { $unwind: "$children" }, { $group: { _id: "$children.job", count: { $sum: 1 } } }, { $project: { k: "$_id", v: "$count", _id: 0 } }, { $group: { _id: null, count: { $push: { k: "$k", v: "$v" } } } }, { $project: { count: { $arrayToObject: "$count" }, _id: 0 } } ])
2. 保留原始children对象的分组方式
如果需要保留每个job对应的原始子对象列表,可以在分组时用$push收集子对象:
db.collection.aggregate([ { $match: { name: "Peter" } }, { $unwind: "$children" }, { $group: { _id: "$children.job", count: { $sum: 1 }, children: { $push: "$children" } } }, // 可选:转为键值对结构 { $project: { k: "$_id", v: { count: "$count", children: "$children" }, _id: 0 } }, { $group: { _id: null, result: { $push: { k: "$k", v: "$v" } } } }, { $project: { result: { $arrayToObject: "$result" }, _id: 0 } } ])
返回结果示例:
{ "result": { "teacher": { "count": 3, "children": [ { "name": "Alex", "age": 33, "job": "teacher", "children": null }, { "name": "Jenny", "age": 31, "job": "teacher", "children": null }, { "name": "Harry", "age": 27, "job": "teacher", "children": null } ] }, "scientist": { "count": 1, "children": [ { "name": "Rob", "age": 28, "job": "scientist", "children": null } ] }, "student": { "count": 1, "children": [ { "name": "Tim", "age": 21, "job": "student", "children": null } ] } } }
关于$unwind的优化
$unwind确实会生成父文档副本,但可以通过$project只保留需要的字段来减少冗余:
// 在$unwind后添加 { $project: { children: 1, _id: 0 } }
内容的提问来源于stack exchange,提问作者jhb
相关产品推荐
相关产品推荐

