MongoDB ищет до 4-5 уровней с массивами

#mongodb #mongoose #mongodb-query #aggregation-framework #aggregate

Вопрос:

Я пытаюсь создать сводный код, который может объединять несколько коллекций и извлекать данные на основе условия

Мои коллекции выглядят следующим образом

Коллекция пользователей(Пример Документа)

 {
"_id":{"$oid":"6137038058d4632824c84872"},
"first_name":"test",
"last_name":".",
"email":"valid@gmail.com",
"enrolled_courses":[
  {
    "completed_lessons":[],
    "completed":false,
    "_id": {"$oid":"6142d1c76d657428903420db"},
    "course_id":{"$oid":"614033510a61aa1f3c8b94ff"}
  },
  {
    "completed_lessons":[],
    "completed":false,
    "_id":{"$oid":"6156d686dcbc58503c7ec679"},
    "course_id":{"$oid":"61486e57460b5a422c6e63ca"}
  },
  {
    "completed_lessons":["616d181e62cb265db07d9273","616d182e62cb265db07d9293"],
    "completed":false,
    "_id":{"$oid":"616d2424149936380c186c2d"},
    "course_id":{"$oid":"616d105662cb265db07d91cf"}
  }
 ]
}
 

Коллекция Курсов(Пример Документа)

 {
 "_id":{"$oid":"6135f735b399f03ba03d74ce"},
 "type":1,
 "enrolled_users":["61374040c27237b1ed87480b"],
 "is_deleted":0,
 "status":1,
 "company_id":{"$oid":"6135f6c9b399f03ba03d74a0"},
 "course":"Course 1"
}
 

Коллекция Модулей(Пример Документа)

 {
 "_id":{"$oid":"616d17fd62cb265db07d9240"},
 "type":1,
 "is_always_available":false,
 "is_deleted":0,
 "status":1,
 "company_id":{"$oid":"6135f6c9b399f03ba03d74a0"},
 "course_id":{"$oid":"616d105662cb265db07d91cf"},
 "module_name":"module 3",
 "due_date":{"$date":"2021-10-18T00:00:00.000Z"}
}
 

Сборник уроков(Пример Документа)

 {
  "_id":{"$oid":"616d184962cb265db07d92cb"},
  "lessson_image":null,
  "status":1,
  "is_deleted": 0,
  "module_id":{"$oid":"616d17e462cb265db07d921f"},
  "lessson_name":"Lesson 3"
}
 

I want to fetch details of all the courses user have enrolled and fetch all course’s modules and its lessons

My expected output should be like following —

 [
{
    //CourseDetail 1 Keys,
    modules: [
        {
            //Module Details
            lessons: [{
                //lessons of this module
            }]
        },
        {
            //Module Details
            lessons: [{
                //lessons of this module
            }]
        }
    ]
},
{
    //CourseDetail 2 Keys,
    modules: [
        {
            //Module Details
            lessons: [{
                //lessons of this module
            }]
        },
        {
            //Module Details
            lessons: [{
                //lessons of this module
            }]
        }
    ]
}
 

]

Мой текущий запрос следующий: в настоящее время он группирует модули и их уроки вместе и привязывает их к одному объекту курса. Выбор модулей и уроков идеален в соответствии с моими требованиями, но массив курсов содержит только 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"
    }
},
{
    $group: {
            
        _id: "$_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: {
        course_id: 1,
        course_name: 1,
        completed_lessons: 1,
        current_lessons: 1,
        completed: 1,
        enrolled_users_count: {
            $size: "$enrolled_users_count"
        },
        modules: 1        
    }
},
{
    $group: {
        _id: "$_id",
        course_id: { $first: "$course_id"},
        course_name: { $first: "$course_name"},
        completed_lessons: { $first: "$completed_lessons"},
        current_lessons: { $first: "$current_lessons"},
        completed: { $first: "$completed"},
        enrolled_users_count: { $first: "$enrolled_users_count"},
        modules: { $first: "$modules"}
    }
}
]);
 

Комментарии:

1. Четыре коллекции — это больше похоже на дизайн реляционной базы данных. Обычно количество коллекций намного меньше, чем количество таблиц в соответствующей реляционной базе данных. Не зная никаких подробностей, я бы предположил, что Курсы, Модули и Уроки смоделированы только в одной коллекции.

2. Согласно функциональности, у нас есть большое количество уроков, связанных с конкретным модулем, и большое количество модулей, связанных с конкретным курсом. Я создал несколько коллекций для этого, потому что мы также можем управлять всем этим по отдельности. Итак, я просто хочу получить все пользовательские курсы(доступные в коллекции enrolled_courses of users), а также все его модули и уроки за один раз.

3. если вы можете упростить данные, удалите дополнительные поля, сохраняйте только 1, вместо идентификаторов используйте числа, и проверьте, существуют ли идентификаторы в других коллекциях. Его уже так много просматривают. Я думаю, вам следует попробовать вложенные поисковые запросы, такие как поиск с помощью конвейера, в котором есть другой поиск с помощью конвейера внутри