MongoDB聚合函数问题:仅返回指定父文档关联的参考数据
MongoDB聚合查询仅返回指定父文档关联参考数据的解决方法
当前聚合查询会返回REF_123和REF_456两个参考数据,但我们只需要返回分页后得到的OF_Code父文档关联的REF_123。问题根源在于原查询先对所有匹配$match条件的父文档执行了$lookup,再做分页筛选,导致拉取了所有关联的参考数据。
文档结构
ParentDocument
[ { "code": "OF_Code", "version": "1", "createdBy": "abc", "attributes": { "associatedProducts": [ { "bundleProducts": [ { "products": [ { "key": "REF_123" } ] } ] } ] } }, { "code": "OF_Code2", "version": "1", "createdBy": "abc", "attributes": { "associatedProducts": [ { "bundleProducts": [ { "products": [ { "key": "REF_123" } ] } ] } ] } }, { "code": "OF_Code3", "version": "1", "createdBy": "abc", "attributes": { "associatedProducts": [ { "bundleProducts": [ { "products": [ { "key": "REF_456" } ] } ] } ] } } ]
ReferencedDocument
[ { "code": "REF_123", "status": "live" }, { "code": "REF_456", "status": "live" }, { "code": "REF_789", "status": "live" } ]
原查询语句
db.parents.aggregate([ { "$match": { "code": { "$in": [ "OF_Code", "OF_Code2", "OF_Code3" ] } } }, { "$lookup": { "from": "reference", "localField": "attributes.associatedProducts.bundleProducts.products.key", "foreignField": "code", "as": "refs", "pipeline": [ { "$project": { "_id": 0 } } ] } }, { "$facet": { "pagination": [ { "$count": "count" } ], "Parent": [ { "$skip": 0 }, { "$limit": 1 } ], "Reference": [ { "$unwind": "$refs" }, { "$group": { "_id": null, "Reference": { "$addToSet": "$refs" } } }, { "$unwind": "$Reference" }, { $replaceWith: "$Reference" } ] } }, { "$unset": "_id" }, { "$unset": "Parent.refs" } ])
当前返回结果
"Reference": [ { "code": "REF_123", "status": "live" }, { "code": "REF_456", "status": "live" } ]
期望返回结果
"Reference": [ { "code": "REF_123", "status": "live" } ]
解决方法
核心思路是先筛选出分页后的目标父文档,再针对该文档执行关联查询,避免拉取所有父文档的关联数据。以下是优化后的查询:
db.parents.aggregate([ { "$match": { "code": { "$in": ["OF_Code", "OF_Code2", "OF_Code3"] } } }, // 先执行分页,筛选出目标父文档 { "$skip": 0 }, { "$limit": 1 }, // 提取当前父文档关联的所有产品key { "$addFields": { "productKeys": { "$reduce": { "input": "$attributes.associatedProducts", "initialValue": [], "in": { "$concatArrays": [ "$$value", { "$reduce": { "input": "$$this.bundleProducts", "initialValue": [], "in": { "$concatArrays": [ "$$value", { "$map": { "input": "$$this.products", "as": "p", "in": "$$p.key" } } ] } } } ] } } } } }, { "$facet": { "pagination": [ { "$count": "count" } ], "Parent": [ // 移除不需要的字段,保持原有结构 { "$unset": ["productKeys"] } ], "Reference": [ // 仅用当前父文档的productKeys关联参考数据 { "$lookup": { "from": "reference", "localField": "productKeys", "foreignField": "code", "as": "refs", "pipeline": [ { "$project": { "_id": 0 } } ] } }, { "$unwind": "$refs" }, { "$replaceWith": "$refs" } ] } }, { "$unset": "_id" } ])
修改说明
- 调整执行顺序:先通过
$skip和$limit筛选出目标父文档,避免对所有匹配$match的文档执行关联操作 - 提取关联key:用
$reduce和$concatArrays嵌套提取父文档中所有关联的产品key,确保只关联当前文档的参考数据 - 分面处理:在
facet中分别处理父文档输出和参考数据输出,保证结构与原查询一致
内容的提问来源于stack exchange,提问作者Hero
相关产品推荐
相关产品推荐

