Come usare $lookup in MongoDB

MongoDB è un popolare database NoSQL che memorizza i dati in raccolte. Le raccolte MongoDB sono costituite da uno o più documenti che contengono i dati effettivi in ​​formato JSON. I documenti sono paragonabili alle righe nei tradizionali database SQL relazionali, mentre le raccolte sono analoghe alle tabelle.

Una funzionalità chiave nei database è la capacità di interrogare i dati memorizzati nel database. L’interrogazione dei dati consente il recupero di informazioni specifiche, l’analisi dei dati, il reporting dei dati e anche l’integrazione dei dati.

Per poter interrogare un database in modo efficace, è fondamentale poter combinare i dati di più tabelle, nel caso di database SQL o più raccolte in database NOSQL, in un unico set di risultati.

In MongoDB $ cerca gli utenti per combinare le informazioni di due raccolte durante le query. Esegue l’equivalente di un join esterno sinistro in un database SQL.

Uso e obiettivo di $lookup

Una funzione importante dei database è l’elaborazione dei dati per ottenere informazioni significative dai dati grezzi.

Ad esempio, se gestisci un’attività di ristorazione, potresti voler analizzare i dati del tuo ristorante per scoprire quanto guadagni ogni giorno, quali cibi sono richiesti nei fine settimana o persino scoprire quante tazze di caffè vendi a ogni ora del giorno.

Per tali esigenze, le semplici query del database non saranno sufficienti. È necessario eseguire query avanzate sui dati archiviati. Per soddisfare tali esigenze, MongoDB ha una funzionalità chiamata pipeline di aggregazione.

Una pipeline di aggregazione è un sistema composto da operazioni componibili denominate fasi, che vengono utilizzate per elaborare i dati per produrre un risultato aggregato finale. Esempi di fasi nella pipeline di aggregazione includono $sort, $match, $group, $merge, $count e $lookup, tra gli altri.

Queste fasi possono essere applicate in qualsiasi ordine in una pipeline di aggregazione. In ogni fase di una pipeline di aggregazione, vengono eseguite diverse operazioni sui dati passati attraverso la pipeline di aggregazione.

$lookup è quindi una fase nella pipeline di aggregazione di MongoDB. $Lookup viene utilizzato per eseguire un join esterno sinistro tra due raccolte in un database MongoDB. Un join esterno sinistro combina tutti i documenti o le voci a sinistra con i documenti o le voci corrispondenti a destra.

Ad esempio, considera le due raccolte seguenti, che sono state rappresentate in formato tabellare per una più facile comprensione:

raccolta_ordini:

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

raccolta_clienti:

customer_numcustomer_namecustomer_emailcustomer_phone100John [email protected] [email protected]

Se eseguiamo un left outer join sulle raccolte di cui sopra utilizzando il campo customer_id, che appare in order_collection, con order_collection come raccolta di sinistra e customers_collection come raccolta di destra, il risultato conterrà tutti i documenti nella Orders Collection e i documenti nella Customers Collection che hanno un customer_num che corrisponde a un customer_id di uno qualsiasi dei record nella Orders Collection.

Il risultato finale dell’operazione di join esterno sinistro sulle raccolte ordini e clienti ha il seguente aspetto se rappresentato in formato tabulare:

Si noti che per il cliente con customer_id 101 nella raccolta ordini, che non aveva un valore customer_num corrispondente nella raccolta clienti, i valori corrispondenti mancanti dalla tabella cliente sono stati riempiti con null.

$lookup esegue un rigoroso confronto di uguaglianza tra i campi e recupera l’intero documento corrispondente e non solo i campi corrispondenti.

Sintassi $ricerca

La sintassi per $lookup è la seguente:

{
   $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 ha quattro parametri:

  • from – rappresenta la raccolta da cui vogliamo cercare i documenti. Nel nostro esempio precedente usando orders_collection e customers_collection, avremmo messo customers_collection come from the collection.
  • localField: questo è un campo nella raccolta di lavoro o primaria che utilizziamo per confrontare i campi nella nostra raccolta from (customers_collection nel nostro caso). Nell’esempio precedente, localField sarebbe customer_id che si trova in orders_collection.
  • foreignField – questo è il campo che vogliamo confrontare nella raccolta che specifichiamo in from. Nel nostro esempio, questo sarebbe customer_num trovato nella customer_collection che usiamo come nostro valore in from
  • as – questo è un nuovo nome di campo che specifichiamo per rappresentare il campo che verrà visualizzato nel nostro documento, che contiene i documenti risultanti dalle corrispondenze tra localField e foreignField. Tutte queste corrispondenze vengono inserite in un array in questo campo. Se non ci sono corrispondenze, questo campo conterrà un array vuoto.

Dalle nostre due raccolte precedenti, utilizzeremo il seguente codice per eseguire un’operazione $lookup sulle due raccolte con orders_collection come raccolta di lavoro o primaria.

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

Si noti che il campo as può essere qualsiasi valore stringa. Tuttavia, se gli dai un nome già esistente nel documento di lavoro, quel campo verrà sovrascritto.

Unione di dati da più raccolte

MongoDB $lookup è una fase utile in una pipeline di aggregazione in MongoDB. Sebbene non sia un requisito che una pipeline di aggregazione in MongoDB debba avere una fase $lookup, la fase è fondamentale quando si eseguono query complesse che richiedono l’unione di dati tra più raccolte.

La fase $lookup esegue un left outer join su due raccolte che determina la creazione di un nuovo campo o la sovrascrittura dei valori di un campo esistente con un array contenente documenti di un’altra raccolta.

Questi documenti vengono selezionati in base alla presenza o meno di valori che corrispondono ai valori del campo con cui vengono confrontati. Il risultato finale è un campo contenente un array di documenti nel caso in cui siano state trovate corrispondenze o un array vuoto nel caso in cui non siano state trovate corrispondenze.

Considera le raccolte dei dipendenti e dei progetti mostrate di seguito.

Possiamo usare il seguente codice per unire le due raccolte:

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

Il risultato di questa operazione è una combinazione delle due collezioni. Il risultato sono i progetti e tutti i dipendenti assegnati a ciascun progetto. I dipendenti sono rappresentati in un array.

Fasi della pipeline che possono essere utilizzate insieme a $lookup

Come accennato in precedenza, $lookup è una fase in una pipeline di aggregazione MongoDB e può essere utilizzata insieme ad altre fasi della pipeline di aggregazione. Per mostrare come queste fasi possono essere utilizzate insieme a $lookup, utilizzeremo le seguenti due raccolte a scopo illustrativo.

In MongoDB, sono archiviati in formato JSON. Ecco come appaiono le raccolte di cui sopra in MongoDB.

Alcuni esempi di fasi della pipeline di aggregazione che possono essere utilizzate insieme a $lookup includono:

$corrispondenza

$match è una fase della pipeline di aggregazione utilizzata per filtrare il flusso di documenti per consentire solo ai documenti che soddisfano la condizione specificata di passare alla fase successiva nella pipeline di aggregazione. Questa fase viene utilizzata al meglio all’inizio della pipeline per rimuovere i documenti che non saranno necessari e quindi ottimizzare la pipeline di aggregazione.

Utilizzando le due raccolte precedenti, puoi combinare $match e $lookup in questo modo:

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

$match viene utilizzato per filtrare gli utenti dagli Stati Uniti. Il risultato di $match viene quindi combinato con $lookup per ottenere i dettagli dell’ordine degli utenti dagli Stati Uniti. Il risultato dell’operazione sopra descritta è mostrato di seguito:

$progetto

$project è una fase utilizzata per rimodellare i documenti specificando quali campi includere, escludere o aggiungere ai documenti. Ad esempio, nel caso in cui tu stia elaborando documenti con dieci campi ciascuno, ma solo quattro campi nei documenti contengono i dati necessari per l’elaborazione dei dati, puoi utilizzare $project per filtrare i campi che non ti servono.

Ciò consente di evitare l’invio di dati non necessari alla fase successiva della pipeline di aggregazione.

Possiamo combinare $lookup e $project in questo modo:

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

Quanto sopra combina le raccolte di utenti e ordini utilizzando $lookup, quindi $project viene utilizzato per visualizzare solo il nome di ciascun utente e l’importo speso da ciascun utente. $project viene utilizzato anche per rimuovere il campo _id dai risultati. Il risultato dell’operazione sopra descritta è mostrato di seguito:

$rilassati

$unwind è una fase di aggregazione utilizzata per decostruire o rimuovere un campo dell’array creando nuovi documenti per ogni elemento dell’array. Ciò è utile nel caso in cui si desideri eseguire un’aggregazione sui valori del campo dell’array.

Ad esempio, nell’esempio seguente, nel caso in cui desideri eseguire l’aggregazione sul campo degli hobby, non puoi farlo perché è un array. Tuttavia, puoi utilizzare unwind it utilizzando $unwind e quindi eseguire aggregazioni sui documenti risultanti.

Utilizzando le raccolte utenti e ordini, possiamo usare $lookup e $unwind insieme in questo modo:

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

Nel codice sopra, $lookup restituisce un campo array chiamato orders. $unwind viene quindi utilizzato per rimuovere il campo dell’array. Il risultato di questa operazione è mostrato di seguito: Nota che Alice appare due volte perché aveva due ordini.

Esempi di casi d’uso di $lookup

Quando si esegue l’elaborazione dei dati, $lookup è uno strumento utile. Ad esempio, potresti avere due raccolte a cui vuoi unirti in base ai campi delle raccolte che hanno dati simili. Una semplice fase $lookup può essere utilizzata per fare ciò e aggiungere un nuovo campo nelle raccolte primarie, che contengono documenti ottenuti da un’altra raccolta.

Considera le raccolte di utenti e ordini mostrate di seguito:

Le due raccolte possono essere combinate utilizzando $lookup per ottenere il risultato mostrato di seguito:

$lookup può anche essere utilizzato per eseguire join più complessi. $lookup non si limita solo a eseguire l’unione su due raccolte. Puoi implementare più fasi $lookup per eseguire join su più di due raccolte. Considera le tre raccolte mostrate di seguito:

Possiamo utilizzare il codice seguente per eseguire un’unione più complessa tra le tre raccolte per ottenere tutti gli ordini effettuati e anche i dettagli dei prodotti ordinati.

Il codice qui sotto ci permette di fare proprio questo:

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

Il risultato dell’operazione sopra descritta è mostrato di seguito:

Conclusione

Quando si esegue l’elaborazione dei dati che coinvolge più raccolte, $lookup può essere utile in quanto consente di unire i dati e trarre conclusioni basate sui dati archiviati in più raccolte. L’elaborazione dei dati raramente si basa su una sola raccolta.

Per trarre conclusioni significative dai dati, unire i dati di più raccolte è un passaggio fondamentale. Pertanto, prendi in considerazione l’utilizzo della fase $lookup nella tua pipeline di aggregazione MongoDB per consentirti di elaborare meglio i tuoi dati e trarre informazioni significative dai dati grezzi archiviati nelle raccolte.

Puoi anche esplorare alcuni comandi e query MongoDB.