Questo capitolo introduce una spiegazione dettagliata dell'analisi statistica di MongoDB, principalmente realizzata attraverso l'Aggregation Pipeline. È simile allo statement "group by" in SQL. Nella shell di MongoDB, l'analisi statistica è implementata utilizzando la funzione db.collection.aggregate().

Tutorial Prerequisiti

MongoDB Aggregation Pipeline

Passaggi Generali

  • Utilizzare $match per filtrare i dati di destinazione
  • Utilizzare $group per raggruppare e calcolare i dati
  • Utilizzare $sort per ordinare i risultati (opzionale)

Dati di Test

I dati nella collezione orders sono i seguenti

{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }

Funzione di aggregazione

db.collection.aggregate(pipeline) Spiegazione:

  • Il pipeline prende un parametro array, dove ciascun elemento rappresenta una fase di elaborazione.

Esempio

db.orders.aggregate([
                     { $match: { status: "A" } },  // Prima fase
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },   // Seconda fase
                     { $sort: { total: -1 } }  // Terza fase
                   ])

Equivalente SQL

select sum(amount) as total from orders 
        where status="A" 
        group by cust_id 
        order by total desc

Fase $match

Formato:

{ $match: { <query> } }

Spiegazione:

  • <query> condizioni di interrogazione MongoDB

Viene utilizzato per impostare le condizioni di interrogazione. Se si ignora $match, implica l'interrogazione di tutti i dati.

Suggerimento: se non si è familiarizzati con la sintassi di interrogazione di MongoDB, fare riferimento ai capitoli precedenti.

Fase $group

Simile alla clausola group by in SQL, viene utilizzata per raggruppare i dati e quindi eseguire una serie di calcoli statistici sui dati raggruppati.

Utilizzo di base di $group

Sintassi:

{
  $group:
    {
      _id: <espressione>, // Condizione di raggruppamento, ad esempio: raggruppa per quale campo
      <campo1>: { <accumulator1> : <espressione1> },  // Operazione di aggregazione, è possibile aggiungere N operazioni di aggregazione
      ...
    }
 }

Spiegazione:

  • - Nome dell'indicatore statistico personalizzato, possono esserci N in totale
  • - Funzione di aggregazione, simile a sum, avg e altre funzioni di aggregazione di SQL, la differenza è che le funzioni di aggregazione di MongoDB sono nominate con $ come prefisso, ad esempio: $sum, $avg
  • - Parametro della funzione di aggregazione, di solito il valore del campo da contare, facendo riferimento ai campi del documento utilizzando il formato "$nome campo"

Esempio:

db.orders.aggregate([
                     {
                        $group: { 
                            _id: "$cust_id",
                            total: { $sum: "$amount" }, // Aggiungi il primo indicatore calcolato totale, utilizzando l'operatore di somma $sum
                            amount_avg: {$avg: "$amount"}  // Aggiungi il secondo indicatore calcolato avg, utilizzando l'operatore di calcolo della media $avg
                        } 
                    }
               ])

Output:

{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }

Equivalente SQL:

select 
    sum(amount) as  total,
    avg(amount) as amount_avg
from orders 
group by cust_id

Funzioni di Aggregazione di $group

Le funzioni di aggregazione comuni per $group sono le seguenti:

Operatore Descrizione Esempio
$avg Calcola la media {$avg: "$amount"}
$sum Somma {$sum: "$amount"}
$max Valore massimo {$max: "$amount"}
$min Valore minimo {$min: "$amount"}
$first Restituisce i dati dopo l'aggregazione, il contenuto del primo documento {$first: "$amount"}
$last Restituisce i dati dopo l'aggregazione, il contenuto dell'ultimo documento {$last: "$amount"}
$push Restituisce i dati dopo l'aggregazione { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet Restituisce i dati dopo l'aggregazione, differente da $push poiché rimuove i duplicati { $addToSet: "$amount" }

Esempio di $push

db.ordini.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // Valori dei campi ord_date e amount
         }
     }
   ]
)

Output

{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }

Esempio di $addToSet

db.ordini.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all_amount: { $addToSet: "$amount" } // Restituisce tutti i valori distinti di amount
         }
     }
   ]
)

Output

{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }

$sort:

Lo stage $sort è tipicamente posizionato alla fine per ordinare i dati aggregati.

Formato:

{ $sort: { <campo1>: <ordine di ordinamento>, <campo2>: <ordine di ordinamento> ... } }

Spiegazione:

  • , - I nomi dei campi da ordinare, supporta più campi.
  • - La direzione dell'ordinamento, -1 per decrescente, 1 per crescente.

Esempio:

db.ordini.aggregate([
                     { $match: { stato: "A" } },
                     { $group: { _id: "$cust_id", totale: { $sum: "$amount" } } },
                     { $sort: { totale: -1 } }
                   ])

Paginazione dell'Aggregato

Possiamo implementare la paginazione utilizzando gli operatori $limit e $skip.

Esempio:

db.ordini.aggregate([
                     { $match: { stato: "A" } },
                     { $group: { _id: "$cust_id", totale: { $sum: "$amount" } } },
                     { $sort: { totale: -1 } },
					 { $limit: 5 }, // Limita il numero di record restituiti, simile alla dimensione della pagina nella paginazione.
					 { $skip: 1 } // Salta un certo numero di record, simile all'offset in SQL.
                   ])