Присоединяйтесь к нескольким коллекциям после параллельной агрегации в mongodb - PullRequest
1 голос
/ 26 мая 2020

У меня есть коллекция под названием "Reel", в которую встроены объекты.

{
    "_id":"reel_1",
    "category":[
        {
            "_id" : "cat_1",
            "videos": [ {"_id":"vid_1"},{"_id":"vid_2"} ] //_id is reference of Video collection
        },
        {
            "_id" : "cat_2",
            "videos": [ {"_id":"vid_3"},{"_id":"vid_4"} ]
        }
    ]
}

Video - это еще одна коллекция, _id которой упоминается внутри reel- > категория -> видео -> _id

{
    "_id":"vid_1",
    "title":"title 1",
    "groups":[{"_id":"group_1"},{"_id":"group_2"}]
},
{
    "_id":"vid_2",
    "title":"title 2",
    "groups":[{"_id":"group_1"},{"_id":"group_4"}]
},
{
    "_id":"vid_3",
    "title":"title 3",
    "groups":[{"_id":"group_1"},{"_id":"group_2"}]
},
{
    "_id":"vid_4",
    "title":"title 4",
    "groups":[{"_id":"group_3"},{"_id":"group_4"}]
}

Коллекция Document , в которой содержится _id из Катушка и _id из Категория

{
    "_id":"doc_1",
    "title":"document title",
    "assessments":[
        {
            "reel":"reel_1",   // reel reference _id
            "category":"cat_1", // category reference _id
            "groups":[{"_id":"group_1"},{"_id":"group_2"}
            ]
        }
    ]

}

Мне нужно присоединиться и найти все связанные встроенные объекты, у которых есть group_1. Я выполнил соединение между Reel collection и Video collection и работает нормально,

{ $unwind: { path: '$category', preserveNullAndEmptyArrays: true }}, 
{ $unwind: { path: '$category.videos', preserveNullAndEmptyArrays: true }}, 
{
    $lookup: {
        from: 'video',
        localField: 'category.videos._id',
        foreignField: '_id',
        as: 'joinVideo'
    }
}, 
{ $unwind: { path: "$joinVideo", preserveNullAndEmptyArrays: true }}, 
{ $unwind: { path: "$joinVideo.groups", preserveNullAndEmptyArrays: true }}, 
{ $match: { "joinVideo.groups._id": "group_1" }}, 
{ $addFields: { "category.videos": "$joinVideo" }}, 
{
    $group: {
        _id: {
            _id: "$_id",
            category: "$category._id"
        },
        videos: {
            $addToSet: "$category.videos"
        }
    }
}, {
    $group: {
        _id: "$_id._id",
        category: {
            $addToSet: {
                "_id": "$_id.category",
                "videos": "$videos"
            }
        }
    }
}

Коллекция документов должна быть встроена в категорию объект основан на катушке _id и категории _id фильтруется по group_1 . Мой ожидаемый результат:

{
    "_id":"reel_1",
    "category":[
        {
            "_id" : "cat_1",
            "videos": [
                {
                    "_id":"vid_1",
                    "title":"title 1",
                    "groups":[ {"_id":"group_1"},{"_id":"group_2"}]
                },  
                {
                    "_id":"vid_2",
                    "title":"title 2",
                    "groups":[{"_id":"group_1"},{"_id":"group_4"}]
                }   
            ],
            "documents":[
                { // this document comes by reel="reel_1", category="cat_1", filtered by "group_1"
                    "_id":"doc_1",
                    "title":"document title",
                }
            ]
        },
        {
            "_id" : "cat_2",
            "videos": [
                {
                    "_id":"vid_3",
                    "title":"title 3",
                    "groups":[{"_id":"group_1"},{"_id":"group_2"}]
                }               
            ]
        }
    ]
}

Я пробовал разными способами. Но сегодня не повезло. Поскольку я новичок в mongodb, я не мог разобраться в этом. Заранее спасибо.

1 Ответ

1 голос
/ 26 мая 2020

Так как MongoDB v3.6, $lookup позволяет выполнять некоррелированные подзапросы . Это позволяет нам выполнять нестандартные запросы для объединения двух или более коллекций.

Примечание: Объяснение почему нам нужно использовать $expr внутри $lookup конвейера

Пояснение

  1. Мы применяем $unwind для выравнивания $category

  2. Мы выполняем $lookup с 2 условиями:

    video.groups._id == 'group_1' и video._id в reel.category.videos._id

Поскольку $reel.category.videos._id возвращает массив, нам нужно использовать $in оператор

Снова выполняем $lookup с 2 условиями. Он создает поле documents для каждого документа Для динамического удаления полей нам нужно использовать выражения агрегации с именем $$REMOVE, что позволяет нам условно исключить поле из документа Выполняем этап $group до желаемого результата
db.reel.aggregate([
  {
    $unwind: {
      path: "$category",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "video",
      let: {
        videos: "$category.videos._id"
      },
      pipeline: [
        {
          $match: {
            "groups._id": "group_1",
            $expr: {
              $in: [
                "$_id",
                "$$videos"
              ]
            }
          }
        }
      ],
      as: "category.videos"
    }
  },
  {
    $lookup: {
      from: "document",
      let: {
        reel_id: "$_id",
        category_id: "$category._id"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $in: [
                    "$$reel_id",
                    "$assessments.reel"
                  ]
                },
                {
                  $in: [
                    "$$category_id",
                    "$assessments.category"
                  ]
                }
              ]
            }
          }
        },
        {
          $project: {
            _id: 1,
            title: 1
          }
        }
      ],
      as: "category.documents"
    }
  },
  {
    $addFields: {
      "category.documents": {
        $cond: [
          {
            $eq: [
              {
                $size: "$category.documents"
              },
              0
            ]
          },
          "$$REMOVE",
          "$category.documents"
        ]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      category: {
        $push: "$category"
      }
    }
  }
])

MongoPlayground

...