Як використовувати $lookup у MongoDB

MongoDB — популярна база даних NoSQL, яка зберігає дані в колекціях. Колекції MongoDB складаються з одного або кількох документів, які містять фактичні дані у форматі JSON. Документи можна порівняти з рядками в традиційних реляційних базах даних SQL, тоді як колекції аналогічні таблицям.

Ключовою функціональністю баз даних є можливість запитувати дані, що зберігаються в базі даних. Запит даних дозволяє отримувати певну інформацію, аналізувати дані, звітувати про дані, а також інтегрувати дані.

Щоб мати змогу ефективно запитувати базу даних, дуже важливо мати можливість об’єднати дані з кількох таблиць, у випадку баз даних SQL або кількох колекцій у базах даних NOSQL, у єдиний набір результатів.

У MongoDB $lookup користувачі об’єднують інформацію з двох колекцій під час запиту. Він виконує еквівалент лівого зовнішнього об’єднання в базі даних SQL.

Використання та призначення $lookup

Важливою функцією баз даних є обробка даних для отримання значущої інформації з вихідних даних.

Наприклад, якщо ви керуєте ресторанним бізнесом, ви можете проаналізувати дані свого ресторану, щоб дізнатися, скільки ви готуєте щодня, які страви є на вимогу у вихідні, або навіть дізнатися, скільки чашок кави ви продаєте в кожну годину дня.

Для таких потреб простих запитів до бази даних буде недостатньо. Вам потрібно виконати розширені запити до даних, які ви зберегли. Щоб задовольнити такі потреби, MongoDB має функцію під назвою конвеєр агрегації.

Конвеєр агрегації – це система, що складається з компонованих операцій, званих етапами, які використовуються для обробки даних для отримання остаточного сукупного результату. Приклади етапів у конвеєрі агрегації включають $sort, $match, $group, $merge, $count і $lookup, серед інших.

Ці етапи можна застосовувати в будь-якому порядку в конвеєрі агрегації. На кожному етапі конвеєра агрегації над даними, що передаються через конвеєр агрегації, виконуються різні операції.

Таким чином, $lookup є етапом конвеєра агрегації MongoDB. $Lookup використовується для виконання лівого зовнішнього об’єднання між двома колекціями в базі даних MongoDB. Ліве зовнішнє об’єднання поєднує всі документи або записи зліва з відповідними документами або записами справа.

Наприклад, розглянемо дві колекції нижче, які представлено у форматі таблиці для легшого розуміння:

збір_замовлень:

order_idcustomer_idorder_datetotal_amount11002022-05-0150.0021012022-05-0275.0031022022-05-03100.00

customer_collection:

customer_numcustomer_namecustomer_emailcustomer_phone100John [email protected] [email protected]

Якщо ми виконаємо ліве зовнішнє об’єднання наведених вище колекцій за допомогою поля customer_id, яке відображається в order_collection, де order_collection є лівою колекцією, а customer_collection – правою колекцією, результат міститиме всі документи в колекції замовлень і документи у колекції клієнтів, які мають customer_num, який відповідає customer_id будь-якого із записів у колекції замовлень.

Кінцевий результат операції лівого зовнішнього об’єднання колекцій замовлень і клієнтів виглядає так, якщо його подати в табличному форматі:

Зверніть увагу, що для клієнта з customer_id 101 у колекції замовлень, який не мав відповідного значення customer_num у колекції клієнтів, відсутні відповідні значення з таблиці клієнтів було заповнено нулем.

$lookup виконує суворе порівняння рівності між полями та отримує весь документ, який відповідає, а не лише поля, які відповідають.

Синтаксис $lookup

Синтаксис $lookup такий:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

$lookup має чотири параметри:

  • from – представляє колекцію, з якої ми хочемо шукати документи. У нашому попередньому прикладі з використанням orders_collection і customers_collection ми поставили customer_collection як елемент із колекції.
  • localField – це поле в робочій або первинній колекції, яке ми використовуємо для порівняння з полями в нашій колекції from (customers_collection у нашому випадку). У наведеному вище прикладі localField буде customer_id, який міститься в orders_collection.
  • ForeignField – це поле, з яким ми хочемо порівняти в колекції, у якій ми вказуємо. У нашому прикладі це буде customer_num, знайдений у customer_collection, який ми використовуємо як наше значення
  • як – це нове ім’я поля, яке ми вказуємо для представлення поля, яке відображатиметься в нашому документі, який містить документи, отримані в результаті збігів між localField і ForeignField. Усі ці збіги поміщаються в масив у цьому полі. Якщо збігів немає, це поле міститиме порожній масив.

З наших двох попередніх колекцій ми використовували б наступний код для виконання операції $lookup над двома колекціями з orders_collection як нашою робочою або основною колекцією.

{
    $lookup: {
      from: "customers_collection",
      localField: "customer_id",
      foreignField: "customer_num",
      as: "customer_info"
 }

Зауважте, що поле as може бути будь-яким рядковим значенням. Однак якщо ви дасте йому назву, яка вже існує в робочому документі, це поле буде перезаписано.

Об’єднання даних із кількох колекцій

MongoDB $lookup є корисним етапом у конвеєрі агрегації в MongoDB. Хоча конвеєр агрегації в MongoDB не обов’язково повинен мати етап $lookup, цей етап є вирішальним під час виконання складних запитів, які потребують об’єднання даних у кількох колекціях.

Етап $lookup виконує ліве зовнішнє об’єднання двох колекцій, у результаті чого створюється нове поле або значення існуючого поля перезаписуються масивом, що містить документи з іншої колекції.

Ці документи вибираються на основі того, чи мають вони значення, які відповідають значенням поля, з яким вони порівнюються. Кінцевим результатом є поле, що містить масив документів, якщо збіги знайдено, або порожній масив, якщо збігів не знайдено.

Розгляньте колекції співробітників і проектів, показані нижче.

Ми можемо використати такий код, щоб об’єднати дві колекції:

db.projects.aggregate([
   {
      $lookup: {
         from: "employees",
         localField: "employees",
         foreignField: "_id",
         as: "assigned_employees"
      }
   }
])

Результатом цієї операції є поєднання двох колекцій. Результатом є проекти та всі співробітники, призначені для кожного проекту. Співробітники представлені в масиві.

Етапи конвеєра, які можна використовувати разом із $lookup

Як згадувалося раніше, $lookup є етапом конвеєра агрегації MongoDB, і його можна використовувати разом з іншими етапами конвеєра агрегації. Щоб показати, як ці етапи можна використовувати разом із $lookup, ми використаємо наступні дві колекції для ілюстрації.

У MongoDB вони зберігаються у форматі JSON. Ось так виглядають наведені вище колекції в MongoDB.

Деякі приклади етапів конвеєра агрегації, які можна використовувати разом із $lookup, включають:

$збіг

$match — це етап конвеєра агрегації, який використовується для фільтрації потоку документів, щоб дозволити лише тим документам, які відповідають заданій умові, перейти до наступного етапу конвеєра агрегації. Цей етап найкраще використовувати на початку конвеєра, щоб видалити документи, які не знадобляться, і таким чином оптимізувати конвеєр агрегації.

Використовуючи дві попередні колекції, ви можете поєднати $match і $lookup так:

db.users.aggregate([
   {
      $match: {
         country: "USA"
      }
   },
   {
      $lookup: {
         from: "orders",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   }
])

$match використовується для фільтрації користувачів із США. Результат $match потім поєднується з $lookup, щоб отримати деталі замовлення користувачів із США. Результат описаної вище операції показано нижче:

$проект

$project — це етап, який використовується для зміни форми документів шляхом визначення полів, які слід включити, виключити або додати до документів. Наприклад, якщо ви обробляєте документи з десятьма полями в кожному, але лише чотири поля в документах містять дані, необхідні для обробки даних, ви можете використовувати $project, щоб відфільтрувати непотрібні вам поля.

Це дозволяє уникнути надсилання непотрібних даних на наступний етап конвеєра агрегації.

Ми можемо поєднати $lookup і $project так:

db.users.aggregate([
   {
      $lookup: {
         from: "orders",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   },
   {
      $project: {
         name: 1,
         _id: 0,
         total_spent: { $sum: "$orders.price" }
      }
   }
])

Наведене вище поєднує колекції користувачів і замовлень за допомогою $lookup, потім $project використовується лише для відображення імені кожного користувача та суми, витраченої кожним користувачем. $project також використовується для видалення поля _id із результатів. Результат описаної вище операції показано нижче:

$розмотати

$unwind — це етап агрегації, який використовується для деконструювання або розгортання поля масиву, створюючи нові документи для кожного елемента в масиві. Це корисно, якщо ви хочете виконати агрегацію значень полів масиву.

Наприклад, у прикладі нижче, якщо ви хочете запустити агрегацію в полі hobbies, ви не можете це зробити, оскільки це масив. Однак ви можете використати його unwind за допомогою $unwind, а потім виконати агрегування отриманих документів.

Використовуючи колекції користувачів і замовлень, ми можемо використовувати $lookup і $unwind разом таким чином:

db.users.aggregate([
   {
      $lookup: {
         from: "orders",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   },
   {
      $unwind: "$orders"
   }
])

У наведеному вище коді $lookup повертає поле масиву під назвою orders. Потім $unwind використовується для розгортання поля масиву. Результат цієї операції показано нижче: Зауважте, що Аліса з’являється двічі, оскільки вона мала два замовлення.

Приклади використання $lookup

Під час обробки даних $lookup є корисним інструментом. Наприклад, у вас можуть бути дві колекції, які ви хочете об’єднати на основі полів у колекціях, які містять подібні дані. Для цього можна використати простий етап $lookup і додати нове поле в основні колекції, які містять документи, отримані з іншої колекції.

Розглядає колекції користувачів і замовлень, показані нижче:

Дві колекції можна поєднати за допомогою $lookup, щоб отримати результат, показаний нижче:

$lookup також можна використовувати для виконання більш складних об’єднань. $lookup не обмежується лише об’єднанням двох колекцій. Ви можете реалізувати кілька етапів $lookup для виконання об’єднань більш ніж двох колекцій. Розглянемо три колекції, показані нижче:

Ми можемо використати наведений нижче код, щоб виконати складніше об’єднання трьох колекцій, щоб отримати всі зроблені замовлення, а також деталі замовлених продуктів.

Наведений нижче код дозволяє нам це зробити:

db.orders.aggregate([
   {
      $lookup: {
         from: "order_items",
         localField: "_id",
         foreignField: "order_id",
         as: "order_items"
      }
   },
   {
      $unwind: "$order_items"
   },
   {
      $lookup: {
         from: "products",
         localField: "order_items.product_id",
         foreignField: "_id",
         as: "product_details"
      }
   },
   {
      $group: {
         _id: "$_id",
         customer: { $first: "$customer" },
         total: { $sum: "$order_items.price" },
         products: { $push: "$product_details" }
      }
   }
])

Результат описаної вище операції показано нижче:

Висновок

Під час обробки даних із залученням кількох колекцій $lookup може бути корисним, оскільки дозволяє об’єднувати дані та робити висновки на основі даних, що зберігаються в кількох колекціях. Обробка даних рідко покладається лише на одну колекцію.

Щоб зробити значущі висновки з даних, ключовим кроком є ​​об’єднання даних у кількох колекціях. Тому подумайте про використання стадії $lookup у вашому конвеєрі агрегації MongoDB, щоб ви могли краще обробляти свої дані та отримувати значущу інформацію з необроблених даних, що зберігаються в колекціях.

Ви також можете дослідити деякі команди та запити MongoDB.