如何从MongoDB含多层对象数组的集合中获取指定数据?
解决MongoDB多层嵌套数组过滤问题
你需要过滤两层嵌套数组的数据,findOne中的$elemMatch仅支持单层数组匹配,因此需要通过聚合管道来实现需求。以下是两种对应你期望结果的实现方式:
方式一:直接获取目标子文档
通过$unwind展开数组,逐层筛选后提取目标字段:
db.collection.aggregate([ // 第一步:筛选PlayerUid=1的文档 { $match: { PlayerUid: 1 } }, // 展开ListData数组,便于后续筛选 { $unwind: "$ListData" }, // 筛选ListData中Id=101的项 { $match: { "ListData.Id": 101 } }, // 展开ListInfo数组 { $unwind: "$ListData.ListInfo" }, // 筛选ListInfo中Uid=5的项 { $match: { "ListData.ListInfo.Uid": 5 } }, // 仅保留需要的字段,去除默认_id { $project: { _id: 0, Uid: "$ListData.ListInfo.Uid", content: "$ListData.ListInfo.content" } } ])
执行结果:
{ "Uid" : 5, "content" : "Which I wanted" }
方式二:保留外层结构的过滤结果
使用$filter和$map操作符,在保留外层文档结构的同时,仅保留符合条件的嵌套数组项:
db.collection.aggregate([ { $match: { PlayerUid: 1 } }, { $project: { _id: 0, PlayerUid: 1, ListData: { // 过滤ListData数组,只保留Id=101的元素 $filter: { input: "$ListData", cond: { $eq: ["$$this.Id", 101] } } } } }, { $project: { PlayerUid: 1, ListData: { $map: { input: "$ListData", as: "listItem", in: { Id: "$$listItem.Id", // 过滤ListInfo数组,只保留Uid=5的元素 ListInfo: { $filter: { input: "$$listItem.ListInfo", cond: { $eq: ["$$this.Uid", 5] } } } } } } } } ])
执行结果(注:你示例中的Id存在笔误,正确应为101而非100):
{ "PlayerUid" : 1, "ListData" : [ { "Id" : 101, "ListInfo" : [ { "Uid" : 5, "content" : "Which I wanted" } ] } ] }
注意事项
- 上述操作支持MongoDB 3.2及以上版本;
- 若集合数据量较大,务必先通过
$match缩小处理范围,避免全表扫描; findOne无法直接处理多层嵌套数组的精准过滤,聚合管道是此类场景的标准解决方案。
内容的提问来源于stack exchange,提问作者Yan Boris
相关产品推荐
相关产品推荐

