Как использовать агрегат mongodb для обогащения объектов с помощью $lookup?

#python #mongodb #mongodb-query #aggregation-framework #pymongo

Вопрос:

Я использую Pymongo для запуска агрегатных трубопроводов против нашего Mongodb.

У меня есть следующие коллекции:

Пользователи

 {
  _id: 1,
  name: 'John Doe',
  age: 30
},
{
  _id: 2,
  name: 'Jane Doe',
  age: 20
}

 

Адреса

 {
  _id: 10,
  name: 'Miami'
},
{
  _id: 20,
  name: 'Orlando'
}
 

Контакты

 {
  _id: 100,
  contacts: [
    {
      user_id: 1,
      location_id: 10,
    },
    {
      user_id: 2,
      location_id: 20,
    }
  ]
}
 

В результате агрегатного конвейера мне нужно:

 {
  _id: 100,
  contacts: [
    {
      user_id: 1,
      user_name: 'John Doe',
      user_age: 30,
      location_id: 10,
      location_name: 'Miami'
    },
    {
      user_id: 2,
      user_name: 'Jane Doe',
      user_age: 20,
      location_id: 20,
      location_name: 'Orlando'
    }
  ]
}
 

Я попробовал несколько запросов с использованием «$lookup», но я просто получаю новый массив вместо того, чтобы помещать значения в один и тот же массив/объект.

Как я могу получить желаемый результат ?

Ответ №1:

Вы можете использовать этот запрос агрегации:

  • Сначала $unwind нужно деконструировать массив и получить значения для объединения
  • Затем два $lookup , чтобы объединить значения и создать массивы users и locations .
  • Поскольку _id используется значение из массива, которое вы хотите, является первым (это должно быть только одно значение, но если существует несколько повторяющихся значений), поэтому вы можете использовать $arrayElemAt .
  • Затем $project , чтобы получить имя поля, которое вы хотите.
  • И $group перегруппировать ценности.
 db.contacts.aggregate([
  {
    "$unwind": "$contacts"
  },
  {
    "$lookup": {
      "from": "users",
      "localField": "contacts.user_id",
      "foreignField": "_id",
      "as": "users"
    }
  },
  {
    "$lookup": {
      "from": "locations",
      "localField": "contacts.location_id",
      "foreignField": "_id",
      "as": "locations"
    }
  },
  {
    "$set": {
      "users": {
        "$arrayElemAt": [
          "$users",
          0
        ]
      },
      "locations": {
        "$arrayElemAt": [
          "$locations",
          0
        ]
      }
    }
  },
  {
    "$project": {
      "contacts": {
        "user_id": 1,
        "location_id": 1,
        "user_name": "$users.name",
        "user_age": "$users.age",
        "location_name": "$locations.name"
      }
    }
  },
  {
    "$group": {
      "_id": "$_id",
      "contacts": {
        "$push": "$contacts"
      }
    }
  }
])
 

Пример здесь