MongoDB中如何查询嵌套数组数据并返回指定子元素
MongoDB查询问题解决方案
一、解决仅返回符合条件audit元素的问题
你之前的两个查询存在的局限:
- 第一个查询使用
items.$投影,MongoDB的位置操作符$仅会返回数组中第一个匹配查询条件的元素,无法获取所有符合条件的项。 - 第二个查询直接指定
{"items":1},只会返回整个items数组,不会对数组内元素做过滤,因此会返回全部数据。
要正确过滤并返回所有符合条件的audit元素,推荐使用聚合管道,以下是两种可行方案:
方案1:用$filter精准筛选数组元素
在投影阶段通过$filter嵌套筛选符合条件的items和audit:
db.Balances.aggregate([ // 先匹配包含目标audit的文档 { $match: { "items.audit.validTo": { $lte: ISODate("2024-01-20T14:24:57.483Z") } } }, // 过滤items中包含符合条件audit的项 { $project: { items: { $filter: { input: "$items", as: "item", cond: { $anyElementTrue: { $map: { input: "$$item.audit", as: "audit", in: { $lte: ["$$audit.validTo", ISODate("2024-01-20T14:24:57.483Z")] } } } } } } } }, // 进一步过滤每个item内的audit元素 { $addFields: { items: { $map: { input: "$items", as: "item", in: { id: "$$item.id", audit: { $filter: { input: "$$item.audit", as: "audit", cond: { $lte: ["$$audit.validTo", ISODate("2024-01-20T14:24:57.483Z")] } } } } } } } } ])
方案2:用$unwind拆分数组后匹配重组
通过拆分数组、匹配条件、重新分组的方式还原结构:
db.Balances.aggregate([ { $match: { "items.audit.validTo": { $lte: ISODate("2024-01-20T14:24:57.483Z") } } }, // 拆分items数组 { $unwind: "$items" }, // 拆分items内的audit数组 { $unwind: "$items.audit" }, // 匹配符合条件的audit元素 { $match: { "items.audit.validTo": { $lte: ISODate("2024-01-20T14:24:57.483Z") } } }, // 按item id分组还原audit数组 { $group: { _id: { _id: "$_id", itemId: "$items.id" }, audit: { $push: "$items.audit" } } }, // 还原items数组结构 { $group: { _id: "$_id._id", items: { $push: { id: "$_id.itemId", audit: "$audit" } } } } ])
二、仅显示audit列表的解决方案
如果希望最终结果只保留符合条件的audit列表,无需items结构,可修改聚合管道直接提取audit元素:
db.Balances.aggregate([ { $match: { "items.audit.validTo": { $lte: ISODate("2024-01-20T14:24:57.483Z") } } }, { $unwind: "$items" }, { $unwind: "$items.audit" }, { $match: { "items.audit.validTo": { $lte: ISODate("2024-01-20T14:24:57.483Z") } } }, // 收集所有符合条件的audit { $group: { _id: null, audit: { $push: "$items.audit" } } }, // 移除自动生成的_id字段 { $project: { _id: 0 } } ])
执行后会得到如下结果:
{ "audit": [ { "validFrom": ISODate("2021-01-20T14:24:57.483Z"), "validTo": ISODate("2024-01-20T14:24:57.483Z") }, { "validFrom": ISODate("2021-01-19T14:24:57.483Z"), "validTo": ISODate("2024-01-19T14:24:57.483Z") } ] }
内容的提问来源于stack exchange,提问作者Suganth
相关产品推荐
相关产品推荐

