如何在Mongoose聚合管道中填充对象数组内的ObjectId字段
Mongoose 聚合嵌套数组字段填充方案
你可以通过两次$lookup关联对应集合,再通过$map将关联结果合并回原images数组的对应对象中,完整聚合阶段示例如下:
const newsStories = await NewsStory.aggregate([ // 你原有业务的其他聚合阶段(如匹配、排序、其他外键填充等) // ... // 1. 关联Media集合,拉取所有image字段对应的数据 { $lookup: { from: "medias", // 替换为Media模型对应的MongoDB集合实际名称,默认是模型名小写复数 localField: "images.image", foreignField: "_id", as: "mediaTempList" } }, // 2. 关联User集合,拉取所有credit字段对应的数据 { $lookup: { from: "users", // 替换为User模型对应的MongoDB集合实际名称 localField: "images.credit", foreignField: "_id", as: "userTempList" } }, // 3. 合并关联数据到原images数组结构中 { $addFields: { images: { $map: { input: "$images", as: "imgItem", in: { caption: "$$imgItem.caption", // 匹配对应Media对象 image: { $first: { $filter: { input: "$mediaTempList", cond: { $eq: ["$$this._id", "$$imgItem.image"] } } } }, // 匹配对应User对象 credit: { $first: { $filter: { input: "$userTempList", cond: { $eq: ["$$this._id", "$$imgItem.credit"] } } } } } } } } }, // 4. 删除临时辅助字段 { $unset: ["mediaTempList", "userTempList"] } ])
注意事项
- 如果你使用的MongoDB版本低于4.4,不支持
$first操作符,可以将其替换为$arrayElemAt: [过滤结果数组, 0],效果一致 - 如果需要过滤关联返回的Media、User字段,可以将
$lookup改为let + pipeline的写法,在pipeline内通过$project指定返回字段 - Mongoose也提供了聚合后调用
.populate('images.image images.credit')的语法糖,底层逻辑与上述原生聚合一致,无性能差异
内容的提问来源于stack exchange,提问作者samman adhikari
相关产品推荐
相关产品推荐

