MST

星途 面试题库

面试题:MongoDB $lookup阶段深度优化及复杂场景应用

存在多个分片的MongoDB集群环境中,有四个集合,集合Employee存储员工信息,有'_id'(员工ID)、'name'(姓名);集合Department存储部门信息,有'_id'(部门ID)、'department_name'(部门名称);集合Project存储项目信息,有'_id'(项目ID)、'project_name'(项目名称);集合Task存储任务信息,有'_id'(任务ID)、'employee_id'(关联员工ID)、'project_id'(关联项目ID)、'department_id'(关联部门ID)。假设数据量非常大,要求通过$lookup阶段查询出每个部门及其员工列表,每个员工需显示姓名以及参与的项目名称列表和任务ID列表,同时要考虑查询性能优化,尽可能减少跨分片查询开销,阐述实现思路并给出具体代码示例。
15.5万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 首先,从Department集合开始查询,因为我们最终要获取每个部门及其相关信息。
  2. 使用$lookupTask集合连接到Department集合,通过department_id关联,这一步可以在同一分片内完成,如果department_id是分片键的一部分或者有合适的索引,性能会较好。
  3. 然后通过$lookupEmployee集合连接到上一步的结果,通过employee_id关联,这一步同样可以优化,如果employee_id是分片键或有索引。
  4. 再通过$lookupProject集合连接到结果,通过project_id关联,同样要利用好索引或分片键。
  5. 最后对结果进行整理,通过$unwind$group等操作获取所需的格式。

具体代码示例

db.Department.aggregate([
    // 左外连接Task集合
    {
        $lookup: {
            from: "Task",
            localField: "_id",
            foreignField: "department_id",
            as: "tasks"
        }
    },
    // 展开tasks数组
    { $unwind: { path: "$tasks", preserveNullAndEmptyArrays: true } },
    // 左外连接Employee集合
    {
        $lookup: {
            from: "Employee",
            localField: "tasks.employee_id",
            foreignField: "_id",
            as: "employee"
        }
    },
    // 展开employee数组
    { $unwind: { path: "$employee", preserveNullAndEmptyArrays: true } },
    // 左外连接Project集合
    {
        $lookup: {
            from: "Project",
            localField: "tasks.project_id",
            foreignField: "_id",
            as: "project"
        }
    },
    // 展开project数组
    { $unwind: { path: "$project", preserveNullAndEmptyArrays: true } },
    // 分组整理结果
    {
        $group: {
            _id: "$_id",
            department_name: { $first: "$department_name" },
            employees: {
                $push: {
                    name: "$employee.name",
                    project_name_list: { $push: "$project.project_name" },
                    task_id_list: { $push: "$tasks._id" }
                }
            }
        }
    }
]);