You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合查询实现课程与学生多对多关联数据拼接

优化MongoDB多集合关联查询:替换课程分组中的学生ID为详情

现有Courses和Students两个集合,Courses集合的studentGroups数组中,每个分组存储的是学生ID列表。当前通过循环查询的方式可以得到正确结果,但多次查询导致效率低下,需要用单条MongoDB聚合查询实现将学生ID替换为Students集合中的完整学生详情。

示例数据

Courses集合数据

[
    {
        _id: 1,
        title: "Maths",
        studentGroups: [
            {
                group: 'A',
                students: [1, 5]
            },
            {
                group: 'B',
                students: [3]
            }
        ]
    },
    {
        _id: 2,
        title: "Chemistry",
        studentGroups: [
            {
                group: 'C',
                students: [2]
            },
            {
                group: 'B',
                students: [4]
            }
        ]
    }
]

Students集合数据

[
    {
        _id:  1,
        name: 'Henry',
        age: 15
    },
    {
        _id:  2,
        name: 'Kim',
        age: 20
    },
    {
        _id:  3,
        name: 'Michel',
        age: 14
    },
    {
        _id:  4,
        name: 'Max',
        age: 16
    },
    {
        _id:  5,
        name: 'Nathan',
        age: 19
    }
]

期望结果

[
    {
        _id: 1,
        title: "Maths",
        studentGroups: [
            {
                group: 'A',
                students: [
                    {
                        _id:  1,
                        name: 'Henry',
                        age: 15
                    },
                    {
                        _id:  5,
                        name: 'Nathan',
                        age: 19
                    }
                ]
            },
            {
                group: 'B',
                students: [
                    {
                        _id:  3,
                        name: 'Michel',
                        age: 14
                    }
                ]
            }
        ]
    },
    {
        _id: 2,
        title: "Chemistry",
        studentGroups: [
            {
                group: 'C',
                students: [
                    {
                        _id:  2,
                        name: 'Kim',
                        age: 20
                    }
                ]
            },
            {
                group: 'B',
                students: [
                    {
                        _id:  4,
                        name: 'Max',
                        age: 16
                    }
                ]
            }
        ]
    }
]

当前低效实现

var courses = Courses.find({}).fetch();

courses.forEach(c => {
    if (c.studentGroups && c.studentGroups.length) {
        c.studentGroups.forEach(s => {
            s.students = Students.find({_id: {$in: s.students}}).fetch()
        })
    }
})

聚合查询解决方案

使用MongoDB聚合管道,通过$lookup、$unwind、$map、$filter、$group等操作实现单条查询完成关联替换:

db.Courses.aggregate([
    // 关联Students集合,一次性获取所有相关学生详情
    {
        $lookup: {
            from: "Students",
            localField: "studentGroups.students",
            foreignField: "_id",
            as: "allStudents"
        }
    },
    // 拆分studentGroups数组,单独处理每个分组
    {
        $unwind: "$studentGroups"
    },
    // 将分组内的学生ID替换为对应详情
    {
        $addFields: {
            "studentGroups.students": {
                $map: {
                    input: "$studentGroups.students",
                    as: "studentId",
                    in: {
                        $first: {
                            $filter: {
                                input: "$allStudents",
                                cond: {$eq: ["$$this._id", "$$studentId"]}
                            }
                        }
                    }
                }
            }
        }
    },
    // 按课程ID重新分组,合并studentGroups数组
    {
        $group: {
            _id: "$_id",
            title: {$first: "$title"},
            studentGroups: {$push: "$studentGroups"}
        }
    },
    // 调整输出字段顺序,匹配原结构
    {
        $project: {
            _id: 1,
            title: 1,
            studentGroups: 1
        }
    }
])

各阶段说明

  1. $lookup:一次性关联Students集合,把当前课程所有相关学生的详情存入allStudents数组,避免多次查询开销。
  2. $unwind:拆分studentGroups数组为单个文档,方便逐个处理分组内的学生ID替换。
  3. $addFields + $map + $filter:遍历分组的学生ID数组,用$filter从allStudents中匹配对应ID的学生详情,$first取唯一匹配结果(学生ID唯一),替换原ID值。
  4. $group:按课程_id重新聚合,将拆分后的分组元素合并回数组,恢复原始文档结构。
  5. $project:调整输出字段顺序,确保和原数据结构一致。

该方案仅需一次聚合查询即可完成所有关联替换,相比循环查询效率大幅提升,数据量越大优势越明显。

内容的提问来源于stack exchange,提问作者StormTrooper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 16:25:21