MongoDB聚合:对$lookup结果分组并映射到带匹配键的模块对象列表
MongoDB聚合实现方案
你现有$lookup逻辑已经可以正确拉取班级关联的所有作业,后续只需要遍历模块数组、匹配对应作业挂载即可,不需要额外做分组操作,完整聚合管道如下:
const lookupPipeline = [ // 原有$lookup关联阶段,保留即可 { $lookup: { from: "assignments", localField: "modules.id", foreignField: "moduleId", as: "assignments" } }, // 重写modules数组,为每个模块挂载对应作业 { $addFields: { modules: { $map: { input: "$modules", as: "module", in: { $mergeObjects: [ // 保留模块原有全部字段 "$$module", { // 过滤匹配当前模块ID的作业 assignments: { $filter: { input: "$assignments", cond: { $eq: ["$$this.moduleId", "$$module.id"] } } } } ] } } } } }, // 可选:移除顶层临时生成的assignments字段,和期望输出结构完全对齐 { $project: { assignments: 0 } } ]
逻辑说明
- 第一阶段
$lookup会将当前班级所有模块关联的作业全部查询到,挂载在文档顶层的assignments数组中 - 第二阶段通过
$addFields重写modules字段:用$map遍历原有模块数组的每一项,通过$mergeObjects保留模块原有属性,同时新增assignments字段;该字段的值通过$filter从顶层作业列表中筛选moduleId与当前模块ID一致的条目,无匹配作业的模块会自动得到空数组,完全符合预期结构 - 最后一个
$project阶段为可选配置,如果不需要保留顶层临时拉取的作业列表就添加,需要保留可以直接删除该阶段
注意:如果
modules.id和assignments.moduleId的字段类型不一致(例如一个是ObjectId类型、一个是字符串类型),需要在$eq判断前通过$toString/$toObjectId做类型转换,否则会出现匹配失败的问题。
内容的提问来源于stack exchange,提问作者user19330089
相关产品推荐
相关产品推荐

