MongoDB多级lookup关联查询:如何正确关联用户已报课程、模块及课时数据
MongoDB多集合条件关联查询聚合语句修正
问题根源
原有代码的核心错误出在分组逻辑:
- 第一次
$group阶段使用用户_id作为分组键,导致同一个用户的所有报名课程被合并到同一分组,$first操作符仅会取第一条课程的基础信息,所有课程的模块被统一推入同一个modules数组,无法按课程拆分 - 末尾多余的第二层
$group进一步把所有聚合结果合并为1条,彻底丢失多课程结构
修正后的聚合代码
let courseDetails = await users.aggregate([ { $match: { _id: mongoose.Types.ObjectId(user._id) } }, { $unwind: "$enrolled_courses" }, { $lookup: { from: 'courses', localField: "enrolled_courses.course_id", foreignField: "_id", as: "courseDetails" } }, { $unwind: { path: "$courseDetails", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "modules", let: { currentCourseId: "$courseDetails._id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$course_id", "$$currentCourseId"] }, { $eq: ["$status", 1] }, { $eq: ["$is_deleted", 0] }, { $or: [ { $eq: ["$is_always_available", true] }, { $gte: ["$due_date", convertedDate] } ] } ] } } }, { $project: { _id: 1, module_name: 1, company_id: 1, course_id: 1 } } ], as: "moduleList" } }, { $unwind: { path: "$moduleList", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "lessons", let: { curentModuleId: "$moduleList._id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$status", 1] }, { $eq: ["$is_deleted", 0] }, { $eq: ["$module_id", "$$curentModuleId"] } ] } } }, { $project: { _id: 1, lessson_name: 1, module_id: 1 } } ], as: "moduleList.lessons" } }, // 核心修改:按课程ID分组,而非用户ID { $group: { _id: "$enrolled_courses.course_id", course_id: { $first: "$enrolled_courses.course_id" }, course_name: { $first: "$courseDetails.course" }, completed_lessons: { $first: "$enrolled_courses.completed_lessons" }, current_lessons: { $first: "$enrolled_courses.current_lessons" }, completed: { $first: "$enrolled_courses.completed" }, enrolled_users_count: { $first: "$courseDetails.enrolled_users" }, // 仅推入当前课程的模块 modules: { $push: "$moduleList" } } }, { $project: { _id: 0, course_id: 1, course_name: 1, completed_lessons: 1, current_lessons: 1, completed: 1, enrolled_users_count: { $size: "$enrolled_users_count" }, // 过滤无有效模块的空值,不需要可以删掉这行 modules: { $filter: { input: "$modules", cond: { $ne: ["$$this", null] } } } } } // 移除原来末尾多余的第二次group ]);
补充说明
如果需要保留没有符合条件模块的课程,删掉$project阶段中modules字段的$filter过滤逻辑即可。
内容的提问来源于stack exchange,提问作者Utkarsh
相关产品推荐
相关产品推荐

