Как сделать $ lookup в поле массива и добавить содержимое внешней таблицы в тот же запрос? - PullRequest
0 голосов
/ 12 октября 2019

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

db_task

{
    "_id" : ObjectId("5d8b522d0cf2579c57bc8ce0"),
    "users" : [ 
        {
            "user_id" : ObjectId("5d8b522d0cf2579e27bc8ce3"),
        "is_finished" : false
        }, 
        {
            "user_id" : ObjectId("5d6f6d25e079b9fb7d858236"),
            "is_finished" : false
        }
    ]
}

В поле «Пользователи» указаны пользователи, которым назначена эта задача. Я хочу выполнить поиск позапрос db_user, который получит мне детали внутри того же встроенного документа.

db_user

{
    "_id" : ObjectId("5d8b522d0cf2579e27bc8ce3"),
    "first_name" : "Harry",
    "last_name" : "Paul"
},

{
    "_id" : ObjectId("5d6f6d25e079b9fb7d858236"),
    "first_name" : "Aaron",
    "last_name" : "Potter"
}

Я попытался выполнить поиск в $ db_user в таблице с помощью «users.user_id», но это привело бы к новому полюи затем я попытался объединить эти массивы с "$ concatArrays", но результат все равно оказался не таким, как я ожидал.

Я хочу получить вывод в формате, похожем на этот

db_task

{
    "_id" : ObjectId("5d8b522d0cf2579c57bc8ce0"),
    "users" : [ 
        {
            "user_id" : ObjectId("5d8b522d0cf2579e27bc8ce3"),
            "is_finished" : false,
            "user_info":{
                 "first_name" : "Harry",
                 "last_name" : "Paul"
              }
        }, 
        {
            "user_id" : ObjectId("5d6f6d25e079b9fb7d858236"),
            "is_finished" : false,
            "user_info":{
                  "first_name" : "Aaron",
                   "last_name" : "Potter"
              }
        }
    ]
}

Ответы [ 3 ]

0 голосов
/ 12 октября 2019

Почти так же, как Вишал Панхания Решение, но мы исключаем user_info._id из внутреннего документа

db.db_task.aggregate([
  {
    $unwind: "$users"
  },
  {
    $lookup: {
      from: "db_user",
      localField: "users.user_id",
      foreignField: "_id",
      as: "user_info"
    }
  },
  {
    $project: {
      users: {
        user_id: 1,
        is_finished: 1,
        user_info: "$user_info"
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      users: {
        $push: "$users"
      }
    }
  },
  {
    $project: {
      "users.user_info._id": 0
    }
  }
])

Результат


[
  {
    "_id": ObjectId("5d8b522d0cf2579c57bc8ce0"),
    "users": [
      {
        "is_finished": false,
        "user_id": ObjectId("5d8b522d0cf2579e27bc8ce3"),
        "user_info": [
          {
            "first_name": "Harry",
            "last_name": "Paul"
          }
        ]
      },
      {
        "is_finished": false,
        "user_id": ObjectId("5d6f6d25e079b9fb7d858236"),
        "user_info": [
          {
            "first_name": "Aaron",
            "last_name": "Potter"
          }
        ]
      }
    ]
  }
]

MongoPlayground

0 голосов
/ 12 октября 2019

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

db.db_task.aggregate([
  {
    $lookup: {
      from: "db_user",
      localField: "users.user_id",
      foreignField: "_id",
      as: "usersInfos"
    }
  },
  {
    $project: {
      users: {
        $map: {
          input: "$usersInfos",
          as: "ui",
          in: {
            $mergeObjects: [
              "$$ui",
              {
                $arrayElemAt: [
                  {
                    $filter: {
                      input: "$users",
                      as: "users",
                      cond: {
                        $eq: [
                          "$$users.user_id",
                          "$$ui._id"
                        ]
                      }
                    }
                  },
                  0
                ]
              }
            ]
          }
        }
      }
    }
  }
])

Будет выводить

[
  {
    "_id": ObjectId("5d8b522d0cf2579c57bc8ce0"),
    "users": [
      {
        "_id": ObjectId("5d6f6d25e079b9fb7d858236"),
        "first_name": "Aaron",
        "is_finished": false,
        "last_name": "Potter",
        "user_id": ObjectId("5d6f6d25e079b9fb7d858236")
      },
      {
        "_id": ObjectId("5d8b522d0cf2579e27bc8ce3"),
        "first_name": "Harry",
        "is_finished": true,
        "last_name": "Paul",
        "user_id": ObjectId("5d8b522d0cf2579e27bc8ce3")
      }
    ]
  }
]

Примечание: как предложено @Valijon, вы можете добавить этап $ project, если вам нужно немного-Устраивайся отсюда.

0 голосов
/ 12 октября 2019

Это работа для тебя.

 db_task.aggregate([
        {
            $match: { '_id': ObjectId("5d8b522d0cf2579c57bc8ce0") }
        },
        {
            $unwind: '$users'
        },
        {
            $lookup: {
                from: 'db_user',
                localField: 'users.user_id',
                foreignField: '_id',
                as: 'user_info'
            }
        },
        {
            $project: {
                $users: {
                    user_id: 1,
                    is_finished: 1,
                    user_info:'$user_info',
                }
            }
        },
        {
            $group: {
                _id: '$_id',
                users: {
                    $push: '$users'
                },
            }
        },
    ])
...