MongoDB过滤嵌套文档数组并保留父字段 应使用find还是aggregate?
MongoDB数组过滤查询解决方案
直接使用aggregate即可实现需求,无需拆分数组后重新组装,$filter操作符可以直接完成数组元素过滤,且会自动保留父级原有字段,同时支持统计符合条件的文档数量和总大小。
完整查询语句
db.doc.aggregate([ // 第一步:匹配符合条件的父文档,减少后续计算量 { $match: { "UserDocuments.id": 1, "UserDocuments.documents.categories": "cat A" } }, // 第二步:过滤documents数组,仅保留categories包含cat A的元素 { $addFields: { "UserDocuments.documents": { $filter: { input: "$UserDocuments.documents", as: "doc", cond: { $in: ["cat A", "$$doc.categories"] } } } } }, // 第三步:自动计算符合条件的文档数量和总大小 { $addFields: { "UserDocuments.count": { $size: "$UserDocuments.documents" }, "UserDocuments.totalSize": { $sum: "$UserDocuments.documents.size" } } } ])
方案说明
- 之前使用
$unwind拆分数组后没有做$group合并,所以会返回多条重复的父文档数据,本方案直接过滤数组,无需拆分,执行效率更高。 - 使用
$addFields而不是$project的优势是不需要手动声明所有要保留的字段,只会更新你指定的documents、count、totalSize三个字段,UserDocuments下的id等其他原有字段会自动保留,不会丢失。 - 如果不需要统计
count和totalSize,直接删除第三步的$addFields阶段即可。
可选find方案(仅过滤数组,不支持统计)
如果你不需要自动计算数量和总大小,用find也可以实现数组过滤:
db.doc.find( { "UserDocuments.id": 1, "UserDocuments.documents.categories": "cat A" }, { "UserDocuments.id": 1, "UserDocuments.documents": { $filter: { input: "$UserDocuments.documents", as: "doc", cond: { $in: ["cat A", "$$doc.categories"] } } } } )
内容的提问来源于stack exchange,提问作者1020rpz
相关产品推荐
相关产品推荐

