MongoDB $lookup с массивом ObjectId

Я работаю над моделью MongoDB для хранения фотографий (/видео). Каждый файл может (необязательно) появляться в одном или нескольких альбомах. Моя модель выглядит так:

> db.files.find().pretty()
    {
        "_id" : ObjectId("600725fbba9901ec2caeba5f"),
        "filename" : "first_picture.jpg",
        "type" : "image",
        "added" : 1611081211,
        "views" : 9,
        "tags" : [ ],
        "albums" : [
            ObjectId("6007d8cfc3b7ef3895f0a8d3")
        ]
    }
    {
        "_id" : ObjectId("600729cf087c3cf47becee3c"),
        "filename" : "first_video.mp4",
        "type" : "video",
        "added" : 1611082191,
        "views" : 1,
        "tags" : [ ],
        "albums" : [ ]
    }
> db.albums.find().pretty()
{
    "_id" : ObjectId("6007d8cfc3b7ef3895f0a8d3"),
    "name" : "Test",
    "created" : 0
}

То, что я пытаюсь сделать, это использовать $lookup для создания одного документа, возвращаемого с документом album и документами из коллекции files, которые имеют ObjectId этого album в массиве альбомов. Поскольку я не хочу загружать все файлы сразу, я хочу ограничить количество возвращаемых файлов.

Мой текущий запрос выглядит так:

db.albums.aggregate([
  {
    $lookup:{
      from: "files",
      let: { "albums": "$albums" },
      pipeline: [
        { "$match": { "$expr": { "$in": ["$_id", "$$albums"] } } },
      ],
      as: "file_list"
    }
  }
])

Судя по примерам, которые я видел, это должно работать. Но когда я запускаю запрос, я получаю:

2021-01-20T13:44:42.779-0800 E QUERY    [thread1] Error: command failed: {
    "ok" : 0,
    "errmsg" : "$in requires an array as a second argument, found: missing",
    "code" : 40081,
    "codeName" : "Location40081"
} : aggregate failed :

Это говорит о том, что поле альбомов не является массивом, но оно есть, и оно присутствует в обоих документах. Что я делаю не так? Я рву на себе волосы!

Изменить: Ожидаемый результат:

{
    "_id" : ObjectId("6007d8cfc3b7ef3895f0a8d3"),
    "name" : "Test",
    "created" : 0.
    "files": [ 
        {
            "_id" : ObjectId("600725fbba9901ec2caeba5f"),
            "filename" : "first_picture.jpg",
            "type" : "image",
            "added" : 1611081211,
            "views" : 9,
            "tags" : [ ],
            "albums" : [
                ObjectId("6007d8cfc3b7ef3895f0a8d3")
            ]
        }
    ]
}

person Phill    schedule 20.01.2021    source источник
comment
Можете ли вы опубликовать, каков ваш ожидаемый результат? Т.к. если я правильно понял, у вас $lookup должно быть наоборот: с files на albums.   -  person J.F.    schedule 21.01.2021
comment
Хорошо, я добавил то, что ожидаю, в качестве выходного документа.   -  person Phill    schedule 21.01.2021


Ответы (1)


Я неверно истолковал документацию.

Мне пришло в голову, что переменные, определенные в $let, могут относиться к основному документу, а не к объединяемым документам. Меня смутило использование входного документа, который я принял за объединяемую коллекцию, хотя на самом деле это означает коллекцию в db.collection.aggregate. Вот почему массива не существует, его нет в документе albums, а в документе files.

Правильный запрос:

db.albums.aggregate([
  {
    $lookup:{
      from: "files",
      let: { "id": "$_id" },
      pipeline: [
        { "$match": { "$expr": { "$in": ["$$id", "$albums"] } } },
      ],
      as: "file_list"
    }
  }
])

Ответ:

{
    "_id" : ObjectId("6008fdce422871592e927b0a"),
    "name" : "Test",
    "created" : 0,
    "file_list" : [
        {
            "_id" : ObjectId("6008fe2c422871592e927b0b"),
            "filename" : "first_picture.jpg",
            "type" : "image",
            "added" : 1611081211,
            "views" : 9,
            "tags" : [ ],
            "albums" : [
                ObjectId("6008fdce422871592e927b0a")
            ]
        }
    ]
}

person Phill    schedule 21.01.2021