MongoDB获取指定内嵌文档并消除unwind数组键的实现方法
解决MongoDB获取指定内嵌文档并去除外层数组键的问题
这问题我之前也碰到过,其实用MongoDB聚合管道里的$replaceRoot(或者4.2+版本的$replaceWith)就能完美解决!下面一步步给你讲清楚:
先看你的场景
假设你的数据模型大概是这样的(外层文档包含一个数组字段,比如叫items):
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "items": [ {"name": "a", "value": 10}, {"name": "b", "value": 20} ] }, { "_id": ObjectId("60d21b4667d0d8992e610c86"), "items": [ {"name": "a", "value": 30}, {"name": "c", "value": 40} ] }
你之前可能用了这样的聚合查询:
db.yourCollection.aggregate([ {$unwind: "$items"}, {$match: {"items.name": "a"}} ])
结果返回的文档会带着外层的_id和items字段,比如:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "items": {"name": "a", "value": 10} }
但你想要的是直接返回内嵌文档本身,也就是:
{"name": "a", "value": 10} {"name": "a", "value": 30}
完美解决方案:加上$replaceRoot
只需要在聚合管道最后加上$replaceRoot阶段,把items字段的内容替换成整个文档的根:
db.yourCollection.aggregate([ // 1. 展开数组,把每个内嵌文档拆成独立的外层文档 {$unwind: "$items"}, // 2. 过滤出name为"a"的内嵌文档 {$match: {"items.name": "a"}}, // 3. 把items的内容提升为根文档,移除外层的冗余字段 {$replaceRoot: {newRoot: "$items"}} ])
如果你的MongoDB版本是4.2及以上,也可以用更简洁的$replaceWith,效果完全一样:
// 替换上面的$replaceRoot阶段 {$replaceWith: "$items"}
进阶:保留父文档的字段(可选)
如果你需要保留父文档的某些字段(比如父文档的_id),可以用$mergeObjects把父字段和内嵌文档合并:
db.yourCollection.aggregate([ {$unwind: "$items"}, {$match: {"items.name": "a"}}, {$replaceRoot: { newRoot: {$mergeObjects: [{"parentId": "$_id"}, "$items"]} }} ])
这样返回的文档会包含父ID和内嵌文档的所有字段:
{"parentId": ObjectId("60d21b4667d0d8992e610c85"), "name": "a", "value": 10}
原理说明
$unwind只是把数组拆分成多个文档,但每个文档还是保留原来的外层结构;而$replaceRoot会完全替换掉当前文档的根,让你指定的内嵌字段成为新的文档主体,这样就得到了你想要的纯内嵌文档格式。
内容的提问来源于stack exchange,提问作者Kodanda Rama Durgarao Poluri
相关产品推荐
相关产品推荐

