Использовать значение find внутри проектора в одном запросе

#mongodb #mongodb-query #aggregation-framework

#mongodb #mongodb-запрос #агрегация-фреймворк

Вопрос:

Вот пример моих данных :

 {
    "_id": ObjectId("5fa7d0e31abef4382b15efd0"),
    "users":
    [
        {
            "_id": ObjectId("5fa667194f22083924eeca9e"),
            "messageId": ObjectId("5fa7d15a1abef4382b15efd2")
        },
        {
            "_id": ObjectId("5fa673a50af228412b0ccf2b"),
            "messageId": ObjectId("5fa7d15a1abef4382b15efd1")
        }
    ],
    "messages":
    [
        {
            "_id": ObjectId("5fa7d0e31abef4382b15efcf"),
            "message": "Hi!",
            "userId": ObjectId("5fa667194f22083924eeca9e")
        },
        {
            "_id": ObjectId("5fa7d15a1abef4382b15efd1"),
            "message": "Hello!",
            "userId": ObjectId("5fa673a50af228412b0ccf2b")
        },
        {
            "_id": ObjectId("5fa7d15a1abef4382b15efd2"),
            "message": "How are you?",
            "userId": ObjectId("5fa667194f22083924eeca9e")
        }
    ]
}
  

Я пытаюсь получить позицию сообщения в массиве «сообщения», определяемую идентификатором MessageId, расположенным в массиве «пользователи».
Вот что я попробовал :

 db.chat.find({ 'users._id': ObjectId("5fa667194f22083924eeca9e") },
             { 'users': 1,
               'index':
               {
                    '$indexOfArray':
                    [
                        '$messages._id',
                        '$users.0.toRead'
                    ]
                },
                'messages.$': 1
              })
  

Я знаю, что это сработает, если я использую :

 db.chat.find({ 'users._id': ObjectId("5fa667194f22083924eeca9e") },
             { 'users': 1,
               'index':
               {
                    '$indexOfArray':
                    [
                        '$messages._id',
                        ObjectId("5fa7d15a1abef4382b15efd2")
                    ]
                },
                'messages.$': 1
              })
  

Но я не могу угадать идентификатор сообщения перед отправкой запроса, и я хотел бы сделать только один запрос и никаких массовых запросов. Возможно ли это сделать? Я хотел бы сделать этот индекс для обоих пользователей. Должен ли я скопировать $indexToArray дважды или есть другой способ?

Ответ №1:

Используя структуру агрегации, действительно возможно достичь желаемого результата, поскольку вы можете использовать операторы $map для сопоставления массива users и включения нового индексного поля с $mergeObjects оператором. Вы все равно можете использовать $indexOfArray оператор для получения позиции идентификатора сообщения. Конечно, вам потребуется $addFields этап конвейера для проецирования этого вновь отображенного users поля и другого свойства документа messages .

Следующий конвейер демонстрирует описанную выше операцию:

 db.chat.aggregate([
 { '$match': { 'users._id': ObjectId("5fa667194f22083924eeca9e") } },
 { '$addFields': {
    'users': {
        '$map': {
            'input': '$users',
            'as': 'u',
            'in': {
                '$mergeObjects': [
                    '$$u',
                    { 'index': { 
                        '$indexOfArray': ['$messages._id', '$$u.messageId']
                    } }
                ]
            }
        }
    } 
 } }
])