MongoDB聚合查询:如何将InspectionItemNotes匹配到对应InspectionItem
问题:InspectionItem与对应InspectionItemNotes关联匹配错误
当前尝试将InspectionItemNotes中的笔记与对应的InspectionItem关联时,出现归属错误:"Water"条目关联了"Fire note 1","Fire"条目关联了"Water note 1",期望每个检查项仅关联属于自己的笔记。
数据集
Inspections集合
{ "_id": {"$oid": "635c37d00017b0adec605f01" }, "REF_InspectionItems": [ {"$oid": "635c37d30017b0adec605f1d" }, {"$oid": "635c37d60017b0adec605f34" } ] }
InspectionItems集合
[ { "_id": {"$oid": "635c37d30017b0adec605f1d"}, "name": "Water", "REF_InspectionItemNotes": [ {"$oid": "635c37d40017b0adec605f26" }, {"$oid": "635c37d50017b0adec605f2c" } ] }, { "_id": {"$oid": "635c37d60017b0adec605f34"}, "name": "Fire", "REF_InspectionItemNotes": [ {"$oid": "635c37d70017b0adec605f3d" } ] } ]
InspectionItemNotes集合
[ { "_id": {"$oid": "635c37d40017b0adec605f26"}, "text": "Water note 1" }, { "_id": {"$oid": "635c37d50017b0adec605f2c"}, "text": "Water note 2" }, { "_id": {"$oid": "635c37d70017b0adec605f3d"}, "text": "Fire note 1" } ]
尝试的聚合管道
[ { '$lookup': { 'from': 'inspectionitems', 'localField': 'REF_InspectionItems', 'foreignField': '_id', 'as': 'inspectionItemsLookup' } }, { '$lookup': { 'from': 'inspectionitemnotes', 'localField': 'inspectionItemsLookup.REF_InspectionItemNotes', 'foreignField': '_id', 'as': 'inspectionItemNotesLookup' } }, { '$project': { 'items': { '$map': { 'input': '$inspectionItemsLookup', 'as': 'temp', 'in': { '$mergeObjects': [ '$$temp', { 'notes': { '$map': { 'input': '$inspectionItemNotesLookup', 'as': 'temp2', 'in': { '$mergeObjects': [ '$$temp2', { 'thisIsNotShowingUp': { '$first': { '$filter': { 'input': '$inspectionItemNotesLookup', 'cond': { '$eq': [ '$$temp2.REF_InspectionItemNotes', '$$this._id' ] } } } } ] } } } } ] } } } } } ]
解决方案
原管道的问题在于第二个$lookup将所有关联的笔记一次性查询到一个数组中,后续$map时未根据当前检查项的REF_InspectionItemNotes过滤对应笔记,导致所有笔记被错误关联给每个检查项。
以下是修正后的聚合管道,通过分步关联确保每个检查项仅匹配自己的笔记:
[ // 第一步:关联InspectionItems { '$lookup': { 'from': 'inspectionitems', 'localField': 'REF_InspectionItems', 'foreignField': '_id', 'as': 'inspectionItemsLookup' } }, // 第二步:拆分每个检查项,为单独关联笔记做准备 { '$unwind': '$inspectionItemsLookup' }, // 第三步:针对每个检查项,关联对应的笔记 { '$lookup': { 'from': 'inspectionitemnotes', 'let': { 'noteIds': '$inspectionItemsLookup.REF_InspectionItemNotes' }, 'pipeline': [ { '$match': { '$expr': { '$in': ['$_id', '$$noteIds'] } } } ], 'as': 'inspectionItemsLookup.notes' } }, // 第四步:将拆分的检查项重新组合为数组 { '$group': { '_id': '$_id', 'items': { '$push': '$inspectionItemsLookup' } } } ]
管道说明
- 先通过
$lookup关联所有目标InspectionItems; - 使用
$unwind将InspectionItems数组拆分为单个文档,便于后续逐个关联笔记; - 再次使用
$lookup,通过let传递当前检查项的笔记ID列表,在子管道中用$match匹配对应的笔记,将结果存入当前检查项的notes字段; - 最后用
$group将拆分的检查项重新组合为数组结构,得到每个检查项关联自身笔记的结果。
内容的提问来源于stack exchange,提问作者MrLister
相关产品推荐
相关产品推荐

