MongoDB聚合查询如何按动态嵌套字段的_id关联替换对应文档
你当前的lookup写法无法直接实现需求,标准$lookup不支持直接遍历动态键对象下的嵌套字段做关联,需要先对嵌套结构做格式转换,批量拉取关联数据后再还原为目标结构,完整实现方案如下:
const result = await DataModel.aggregate([ // 筛选目标文档 { $match: { name: "tub" } }, // 转换动态key对象为可遍历数组,同时提取所有待关联的record_id { $addFields: { dataArray: { $objectToArray: "$data" }, recordIds: { $reduce: { input: { $objectToArray: "$data" }, initialValue: [], in: { $concatArrays: ["$$value", ["$$this.v.record_id"]] } } } } }, // 单次查询拉取所有关联的record文档 { $lookup: { from: "records", localField: "recordIds", foreignField: "_id", as: "allRecords" } }, // 遍历数组条目,替换record_id为实际关联文档 { $addFields: { dataArray: { $map: { input: "$dataArray", as: "item", in: { k: "$$item.k", v: { record: { $arrayElemAt: [ { $filter: { input: "$allRecords", cond: { $eq: ["$$this._id", "$$item.v.record_id"] } } }, 0 ] } } } } } } }, // 将数组还原为原动态key对象结构 { $addFields: { data: { $arrayToObject: "$dataArray" } } }, // 清理中间临时字段 { $project: { dataArray: 0, recordIds: 0, allRecords: 0 } } ])
实现说明
- 由于
data是键名动态("1"/"2"/"3")的对象,无法直接遍历提取内部的record_id,因此先用$objectToArray将其转换为固定结构的数组,同时批量提取所有关联id,单次lookup拉取数据的性能远高于逐字段关联 - 关联完成后通过
$arrayToObject还原为原对象结构,最终返回结果和你预期的格式完全一致 - 注意:如果你的
record_id存储为字符串类型,而records集合的_id是ObjectId类型,需要在提取recordIds时用$toObjectId做类型转换,否则会出现关联匹配失败的问题。
内容的提问来源于stack exchange,提问作者juztcode
相关产品推荐
相关产品推荐

