MongoDB find()查询如何过滤文档数组内的指定元素
MongoDB 过滤嵌套数组元素实现方案
普通find()的基础投影语法不支持自定义条件过滤嵌套数组内的元素,可根据你使用的MongoDB版本选择对应实现方式:
- MongoDB 4.4及以上版本:可直接在
find()中使用聚合投影运算符实现 - 所有版本通用:通过
aggregate()聚合管道实现
方式1:find() 直接实现(4.4+版本支持)
查询语句如下,第一个参数是文档级别的匹配条件,无特殊筛选需求可留空对象,第二个参数使用$filter运算符完成数组元素过滤:
db.your_collection_name.find( {}, // 此处可填写文档级别的筛选条件,例如 { name: "name" } { arr: { $filter: { input: "$arr", cond: { $not: [ { $and: [ // 条件1:内嵌arr数组长度为1 { $eq: [{ $size: "$$this.arr" }, 1] }, // 条件2:内嵌arr的唯一元素值为"abc" { $eq: [{ $arrayElemAt: ["$$this.arr", 0] }, "abc"] } ] } ] } } }, // 声明需要返回的其他顶层字段 name: 1, field1: 1, field2: 1 } )
逻辑说明:$filter会遍历外层arr数组的每一个元素,通过$not排除同时满足「内嵌arr长度为1、唯一元素是"abc"」的元素,剩余元素会被保留在返回结果中,和你给出的预期输出完全一致。
方式2:aggregate() 聚合管道实现(全版本兼容)
如果你的MongoDB版本低于4.4,可使用聚合管道实现,过滤逻辑和上述方式完全一致:
db.your_collection_name.aggregate([ // 文档筛选阶段,无特殊需求可省略 // { $match: { /* 文档级筛选条件 */ } }, { $project: { arr: { $filter: { input: "$arr", cond: { $not: [ { $and: [ { $eq: [{ $size: "$$this.arr" }, 1] }, { $eq: [{ $arrayElemAt: ["$$this.arr", 0] }, "abc"] } ] } ] } } }, name: 1, field1: 1, field2: 1 } } ])
优化:无需手动枚举所有顶层字段
如果你的集合文档顶层字段很多,不想逐个在投影中声明,可以使用$replaceRoot+$mergeObjects自动保留所有原字段,仅替换过滤后的arr数组,示例:
db.your_collection_name.aggregate([ { $replaceRoot: { newRoot: { $mergeObjects: [ "$$ROOT", { arr: { $filter: { input: "$arr", cond: { $not: [ { $and: [ { $eq: [{ $size: "$$this.arr" }, 1] }, { $eq: [{ $arrayElemAt: ["$$this.arr", 0] }, "abc"] } ] } ] } } } } ] } } } ])
注意:该写法仅适用于聚合管道,无法在find()的投影参数中使用。
内容的提问来源于stack exchange,提问作者shr7
相关产品推荐
相关产品推荐

