MongoDB如何查询并过滤数组对象中符合指定条件的元素?
MongoDB查询过滤嵌套数组元素实现方案
你之前写的查询语句无法得到预期结果,核心是两个认知偏差:
- 写在查询条件里的
$elemMatch作用是筛选符合条件的文档:只会返回attachments数组中至少存在1个isDeleted=false元素的文档,会直接漏掉你示例中id=456、所有附件都标记为删除的文档 - 普通find查询默认不会修改返回的字段内容:就算文档被匹配命中,attachments数组也会原样返回所有元素,不会自动剔除isDeleted=true的对象
要实现「返回所有post文档 + 每个文档的attachments仅保留isDeleted=false的对象、无匹配项时返回空数组」的需求,根据你部署的MongoDB版本选择对应写法即可:
方案1:聚合管道实现(兼容MongoDB 3.2+全版本,通用性最强)
使用$filter聚合操作符对数组做遍历过滤,不需要筛选排除任何文档,直接重写每个文档的attachments字段值:
db.post.aggregate([ { $set: { attachments: { $filter: { input: "$attachments", cond: { $eq: ["$$this.isDeleted", false] } } } } } ])
$set操作符会仅重写你指定的attachments字段,其余原有字段(id、uId、msg等)都会原样保留,不需要额外声明。
方案2:find投影过滤(MongoDB 4.4+版本支持,写法更简洁)
MongoDB 4.4版本后支持在find的投影参数中直接使用聚合表达式,无需走聚合管道即可实现相同效果:
db.post.find( {}, // 传入空查询条件,返回集合下所有文档 { id: 1, uId: 1, msg: 1, attachments: { $filter: { input: "$attachments", cond: { $eq: ["$$this.isDeleted", false] } } } } )
使用该写法时注意:除了默认返回的_id字段外,其余你需要返回的字段都要在投影中显式设置为1,否则不会出现在返回结果中。
两种写法执行后的返回结果和你给出的预期完全一致:
- id=123的文档:attachments仅保留未删除的attach1对象
- id=456的文档:无未删除附件,attachments返回空数组
- id=789的文档:attachments保留未删除的attach1对象
避坑提示:不要在查询条件中添加
attachments: {$elemMatch: {isDeleted: false}}规则,否则会把没有未删除附件的文档过滤掉,不符合你查询所有post文档的要求。
内容的提问来源于stack exchange,提问作者Saurabh
相关产品推荐
相关产品推荐

