Jak korzystać z $lookup w MongoDB

MongoDB to popularna baza danych NoSQL, która przechowuje dane w kolekcjach. Kolekcje MongoDB składają się z jednego lub więcej dokumentów zawierających rzeczywiste dane w formacie JSON. Dokumenty są porównywalne do wierszy w tradycyjnych relacyjnych bazach danych SQL, podczas gdy kolekcje są analogiczne do tabel.

Kluczową funkcjonalnością baz danych jest możliwość zapytania o dane przechowywane w bazie danych. Zapytanie o dane pozwala na pozyskiwanie określonych informacji, analizę danych, raportowanie danych, a także integrację danych.

Aby móc skutecznie wysyłać zapytania do bazy danych, kluczowa jest możliwość łączenia danych z wielu tabel, w przypadku baz SQL lub wielu kolekcji w bazach danych NOSQL, w jeden zestaw wyników.

W MongoDB $lookup użytkownicy mogą łączyć informacje z dwóch kolekcji podczas wysyłania zapytań. Wykonuje odpowiednik lewego sprzężenia zewnętrznego w bazie danych SQL.

Użycie i cel usługi $lookup

Ważną funkcją baz danych jest przetwarzanie danych w celu uzyskania sensownych informacji z surowych danych.

Na przykład, jeśli prowadzisz firmę restauracyjną, możesz chcieć przeanalizować dane swojej restauracji, aby dowiedzieć się, ile zarabiasz każdego dnia, jakie produkty spożywcze są na żądanie w weekendy, a nawet dowiedzieć się, ile filiżanek kawy sprzedajesz każdą godzinę dnia.

Na takie potrzeby proste zapytania do bazy danych nie wystarczą. Musisz wykonać zaawansowane zapytania dotyczące przechowywanych danych. Aby sprostać takim potrzebom, MongoDB ma funkcję zwaną potokiem agregacji.

Potok agregacji to system składający się z możliwych do skomponowania operacji zwanych etapami, które służą do przetwarzania danych w celu uzyskania ostatecznego zagregowanego wyniku. Przykłady etapów w potoku agregacji to między innymi $sort, $match, $group, $merge, $count i $lookup.

Te etapy można zastosować w dowolnej kolejności w potoku agregacji. Na każdym etapie potoku agregacji wykonywane są różne operacje na danych przesyłanych przez potok agregacji.

$lookup jest zatem etapem w potoku agregacji MongoDB. $Lookup służy do wykonania lewego sprzężenia zewnętrznego między dwiema kolekcjami w bazie danych MongoDB. Lewe sprzężenie zewnętrzne łączy wszystkie dokumenty lub wpisy po lewej stronie z pasującymi dokumentami lub wpisami po prawej stronie.

Rozważmy na przykład dwie poniższe kolekcje, które zostały przedstawione w formie tabelarycznej dla łatwiejszego zrozumienia:

zamówienia_odbiór:

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

klienci_kolekcja:

numer_klienta nazwa_klientacustomer_emailcustomer_phone100Jan [email protected] [email protected]

Jeśli wykonamy lewe sprzężenie zewnętrzne na powyższych kolekcjach za pomocą pola customer_id, które pojawia się w order_collection, przy czym order_collection jest lewą kolekcją, a customer_collection jest właściwą kolekcją, wynik będzie zawierał wszystkie dokumenty w Orders Collection oraz dokumenty w kolekcji Customers, które mają numer_klienta odpowiadający identyfikatorowi klienta dowolnego rekordu w kolekcji zamówień.

Końcowy wynik operacji lewego sprzężenia zewnętrznego na kolekcjach zamówień i klientów wygląda następująco, gdy jest przedstawiony w formacie tabelarycznym:

Zwróć uwagę, że dla klienta o identyfikatorze_klienta 101 w zbiorze zamówień, który nie miał pasującej wartości numer_klienta w zbiorze klientów, brakujące odpowiednie wartości z tabeli klientów zostały uzupełnione wartością null.

$lookup wykonuje ścisłe porównanie równości między polami i pobiera cały dopasowany dokument, a nie tylko pasujące pola.

$lookup Składnia

Składnia $lookup jest następująca:

{
   $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 ma cztery parametry:

  • from – reprezentuje kolekcję, z której chcemy wyszukać dokumenty. W naszym wcześniejszym przykładzie z wykorzystaniem orders_collection i customer_collection umieścilibyśmy customer_collection jako element z kolekcji.
  • localField – jest to pole w kolekcji roboczej lub podstawowej, którego używamy do porównania z polami w naszej kolekcji from (w naszym przypadkucustomers_collection). W powyższym przykładzie polem localField byłby identyfikator klienta, który znajduje się w zbiorze_zamówień.
  • ForeignField – jest to pole, do którego chcemy porównać w kolekcji, którą określamy w from. W naszym przykładzie byłby to numer_klienta znaleziony w kolekcji_klientów, którego używamy jako naszej wartości w from
  • as – jest to nowa nazwa pola, którą podajemy, aby reprezentować pole, które pojawi się w naszym dokumencie, który zawiera dokumenty wynikające z dopasowań między polem lokalnym a polem obcym. Wszystkie te dopasowania są umieszczane w tablicy w tym polu. Jeśli nie ma dopasowań, to pole będzie zawierać pustą tablicę.

Z naszych dwóch wcześniejszych kolekcji użylibyśmy następującego kodu do wykonania operacji $lookup na dwóch kolekcjach z zbiorem zamówień jako naszą kolekcją roboczą lub podstawową.

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

Zauważ, że pole as może być dowolną wartością ciągu. Jeśli jednak nadasz mu nazwę, która już istnieje w dokumencie roboczym, pole to zostanie nadpisane.

Łączenie danych z wielu kolekcji

MongoDB $lookup to przydatny etap w potoku agregacji w MongoDB. Chociaż nie jest wymagane, aby potok agregacji w MongoDB miał etap $lookup, etap ten ma kluczowe znaczenie podczas wykonywania złożonych zapytań, które wymagają łączenia danych z wielu kolekcji.

Etap $lookup wykonuje lewe sprzężenie zewnętrzne na dwóch kolekcjach, co skutkuje utworzeniem nowego pola lub nadpisaniem wartości istniejącego pola tablicą zawierającą dokumenty z innej kolekcji.

Te dokumenty są wybierane na podstawie tego, czy zawierają wartości pasujące do wartości pola, z którym są porównywane. Wynikiem końcowym jest pole zawierające tablicę dokumentów w przypadku znalezienia dopasowań lub pustą tablicę w przypadku braku dopasowań.

Rozważ kolekcje pracowników i projektów pokazane poniżej.

Możemy użyć następującego kodu, aby połączyć dwie kolekcje:

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

Wynikiem tej operacji jest połączenie dwóch kolekcji. Rezultatem są projekty i wszyscy pracownicy przypisani do każdego projektu. Pracownicy są reprezentowani w tablicy.

Etapy potoku, których można używać razem z $lookup

Jak wspomniano wcześniej, $lookup jest etapem w potoku agregacji MongoDB i może być używany razem z innymi etapami potoku agregacji. Aby pokazać, jak te etapy mogą być używane razem z $lookup, użyjemy dwóch poniższych kolekcji w celach ilustracyjnych.

W MongoDB są one przechowywane w formacie JSON. Tak wyglądają powyższe kolekcje w MongoDB.

Oto kilka przykładów etapów potoku agregacji, których można używać razem z $lookup:

$dopasowanie

$match to etap potoku agregacji używany do filtrowania strumienia dokumentów w celu umożliwienia przejścia do następnego etapu potoku agregacji tylko tym dokumentom, które spełniają dany warunek. Ten etap najlepiej wykorzystać na wczesnym etapie potoku, aby usunąć dokumenty, które nie będą potrzebne, a tym samym zoptymalizować potok agregacji.

Korzystając z dwóch wcześniejszych kolekcji, możesz połączyć $match i $lookup w następujący sposób:

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

$match służy do filtrowania użytkowników z USA. Wynik z $match jest następnie łączony z $lookup, aby uzyskać szczegóły zamówienia użytkowników z USA. Wynik powyższej operacji przedstawiono poniżej:

$projekt

$project to etap służący do przekształcania dokumentów poprzez określanie, które pola mają zostać uwzględnione, wykluczone lub dodane do dokumentów. Na przykład, jeśli przetwarzasz dokumenty z dziesięcioma polami, ale tylko cztery pola w dokumentach zawierają dane potrzebne do przetwarzania danych, możesz użyć $project do odfiltrowania pól, których nie potrzebujesz.

Pozwala to uniknąć wysyłania zbędnych danych do następnego etapu potoku agregacji.

Możemy połączyć $lookup i $project w następujący sposób:

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

Powyższe łączy kolekcje użytkowników i zamówień za pomocą $lookup, a następnie $project służy do wyświetlania tylko nazwy każdego użytkownika i kwoty wydanej przez każdego użytkownika. $project służy również do usuwania pola _id z wyników. Wynik powyższej operacji przedstawiono poniżej:

$rozluźnij się

$unwind to etap agregacji używany do dekonstrukcji lub rozwinięcia pola tablicy, tworząc nowe dokumenty dla każdego elementu w tablicy. Jest to przydatne, jeśli chcesz uruchomić agregację wartości pól tablicy.

Na przykład w poniższym przykładzie, jeśli chcesz uruchomić agregację dla pola hobby, nie możesz tego zrobić, ponieważ jest to tablica. Możesz jednak użyć unwind za pomocą $unwind, a następnie wykonać agregacje na wynikowych dokumentach.

Korzystając z kolekcji użytkowników i zamówień, możemy razem używać $lookup i $unwind w następujący sposób:

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

W powyższym kodzie $lookup zwraca pole tablicowe o nazwie zamówienia. $unwind jest następnie używany do rozwinięcia pola tablicy. Wynik tej operacji pokazano poniżej: Zauważ, że Alicja pojawia się dwa razy, ponieważ miała dwa rozkazy.

Przykłady przypadków użycia $lookup

Podczas przetwarzania danych przydatnym narzędziem jest $lookup. Na przykład możesz mieć dwie kolekcje, które chcesz połączyć na podstawie pól w kolekcjach zawierających podobne dane. W tym celu można użyć prostego etapu $lookup i dodać nowe pole w kolekcjach podstawowych, które zawierają dokumenty pobrane z innej kolekcji.

Bierze pod uwagę użytkowników i zamawia kolekcje pokazane poniżej:

Te dwie kolekcje można połączyć za pomocą $lookup, aby uzyskać wynik pokazany poniżej:

$lookup może być również używany do wykonywania bardziej złożonych połączeń. Funkcja $lookup nie ogranicza się tylko do łączenia dwóch kolekcji. Możesz zaimplementować wiele etapów $lookup, aby wykonać sprzężenia na więcej niż dwóch kolekcjach. Rozważ trzy kolekcje pokazane poniżej:

Możemy użyć poniższego kodu, aby wykonać bardziej złożone połączenie trzech kolekcji, aby uzyskać wszystkie złożone zamówienia, a także szczegóły zamówionych produktów.

Poniższy kod pozwala nam to zrobić:

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" }
      }
   }
])

Wynik powyższej operacji przedstawiono poniżej:

Wniosek

Podczas przetwarzania danych obejmującego wiele kolekcji funkcja $lookup może być przydatna, ponieważ umożliwia łączenie danych i wyciąganie wniosków na podstawie danych przechowywanych w wielu kolekcjach. Przetwarzanie danych rzadko polega na jednym zbiorze.

Aby wyciągnąć sensowne wnioski z danych, kluczowym krokiem jest połączenie danych z wielu kolekcji. Dlatego rozważ wykorzystanie etapu $lookup w potoku agregacji MongoDB, aby umożliwić lepsze przetwarzanie danych i wyciąganie znaczących wniosków z nieprzetworzonych danych przechowywanych w różnych kolekcjach.

Możesz także zapoznać się z niektórymi poleceniami i zapytaniami MongoDB.