如何通过MongoDB查询将嵌套子文档转换为独立文档?
MongoDB聚合:将嵌套文档拆分为独立文档
我正在模拟Firebase Realtime DB的Restful API,由于数据上传时未遵循标准结构,现在需要把嵌套文档拆分成独立文档,这样后续的排序、聚合操作可以直接通过MongoDB查询完成,不用在服务器端处理。
当前$project提取的数据
{ "data": { "8787879798": { "value": 89 }, "c5ca5ebd804b4b1aab82348a4070fa78": { "sample": 78 }, "88dc2f042c3e4aa3a2a2378e48444000": { "sample": 78 }, "7061e88f77754b6e94b3b2ed3bf7513f": { "sample": 78 }, "033f120577c443548d4cdc4425a7767f": { "sample": 78 }, "33fb18ba5e3d41c5a6b9b89433ab231d": { "sample": 78 }, "5f9c6d4bf0e3416b9b963dbf5d15021d": { "sample": 78 } } }
当前使用的聚合查询
[ { $project: { _id: 0, data: "$foo.bar.xyz" } } ]
期望输出
每个子文档成为独立文档
{ "8787879798": { "value": 89 } } { "c5ca5ebd804b4b1aab82348a4070fa78": { "sample": 78 } } { "88dc2f042c3e4aa3a2a2378e48444000": { "sample": 78 } } { "7061e88f77754b6e94b3b2ed3bf7513f": { "sample": 78 } } { "033f120577c443548d4cdc4425a7767f": { "sample": 78 } } { "33fb18ba5e3d41c5a6b9b89433ab231d": { "sample": 78 } } { "5f9c6d4bf0e3416b9b963dbf5d15021d": { "sample": 78 } }
解决方案
通过MongoDB的$objectToArray、$unwind和$replaceRoot三个聚合操作组合,就能实现需求:
- 转换为键值数组:用
$objectToArray把嵌套的data对象转换成包含k(键)和v(值)的数组 - 拆分数组为单文档:用
$unwind将数组拆成多个独立文档,每个文档对应原数组中的一个键值对 - 重构根文档:用
$replaceRoot配合$arrayToObject,把每个键值对重新组合成独立的根文档
完整聚合查询语句:
[ { $project: { _id: 0, data: { $objectToArray: "$foo.bar.xyz" } } }, { $unwind: "$data" }, { $replaceRoot: { newRoot: { $arrayToObject: [[{ k: "$data.k", v: "$data.v" }]] } } } ]
操作说明
$objectToArray: "$foo.bar.xyz":把原嵌套对象转成[{k: "8787879798", v: {value:89}}, ...]格式的数组$unwind: "$data":将数组拆分成7个独立文档,每个文档包含一个data对象$arrayToObject+$replaceRoot:把每个data的k和v重新组合成单个文档,替换当前根文档,最终得到期望的输出格式
内容的提问来源于stack exchange,提问作者Kayvan Shah
相关产品推荐
相关产品推荐

