Ricerca…


introduzione

Aggregations operazioni di Aggregations elaborano i record di dati e restituiscono risultati calcolati. Le operazioni di aggregazione raggruppano i valori di più documenti insieme e possono eseguire una varietà di operazioni sui dati raggruppati per restituire un singolo risultato. MongoDB offre tre modi per eseguire l'aggregazione: la pipeline di aggregazione, la funzione di riduzione della mappa e i metodi di aggregazione a scopo singolo.

Dal manuale di Mongo https://docs.mongodb.com/manual/aggregation/

Sintassi

  • db.collection.aggregate (pipeline, opzioni)

Parametri

Parametro Dettagli
conduttura array (sequenza di operazioni o stadi di aggregazione dei dati)
opzioni documento (opzionale, disponibile solo se la pipeline è presente come array)

Osservazioni

Il framework di aggregazione in MongoDB viene utilizzato per ottenere la funzionalità GROUP BY comune di SQL.

Considerare i seguenti inserimenti nella raccolta transactions denominate per ogni esempio.

> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10,  fee : 2});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 10,  fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10,  fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});

Contare

Come si ottiene il numero di transazioni di debito e credito? Un modo per farlo è usando la funzione count() come sotto.

> db.transactions.count({cr_dr : "D"});

o

> db.transactions.find({cr_dr : "D"}).length();

Ma cosa succede se non si conoscono i possibili valori di cr_dr anticipo. Qui entra in gioco il framework Aggregation. Vedi la seguente query aggregata.

> db.transactions.aggregate( 
      [
          {
              $group : {
                  _id : '$cr_dr', // group by type of transaction
                // Add 1 for each document to the count for this type of transaction
                  count : {$sum : 1}
              }
          }
      ]
  );

E il risultato è

{
    "_id" : "C",
    "count" : 3
}
{
    "_id" : "D",
    "count" : 5
}

Somma

Come ottenere la somma della amount ? Vedere la query aggregata di seguito.

> db.transactions.aggregate( 
     [
         {
             $group : {
                 _id : '$cr_dr',
                 count : {$sum : 1},    //counts the number
                 totalAmount : {$sum : '$amount'}    //sums the amount
             }
         }
     ] 
 );

E il risultato è

{
    "_id" : "C",
    "count" : 3.0,
    "totalAmount" : 120.0
}
{
    "_id" : "D",
    "count" : 5.0,
    "totalAmount" : 410.0
}

Un'altra versione che somma amount e fee .

> db.transactions.aggregate(
      [
          {
              $group : {
                  _id : '$cr_dr',
                  count : {$sum : 1},
                  totalAmount : {$sum : { $sum : ['$amount', '$fee']}}
              }
          }
      ] 
  );

E il risultato è

{
    "_id" : "C",
    "count" : 3.0,
    "totalAmount" : 128.0
}    
{
    "_id" : "D",
    "count" : 5.0,
    "totalAmount" : 422.0
}

Media

Come ottenere l'importo medio delle transazioni di debito e credito?

> db.transactions.aggregate(
    [
        {
            $group : {
                _id : '$cr_dr', // group by type of transaction (debit or credit)
                count : {$sum : 1},    // number of transaction for each type
                totalAmount : {$sum : { $sum : ['$amount', '$fee']}},    // sum
                averageAmount : {$avg : { $sum : ['$amount', '$fee']}}   // average
            }
        }
    ] 
)

Il risultato è

{
    "_id" : "C", // Amounts for credit transactions
    "count" : 3.0,
    "totalAmount" : 128.0,
    "averageAmount" : 40.0
}
{
    "_id" : "D", // Amounts for debit transactions
    "count" : 5.0,
    "totalAmount" : 422.0,
    "averageAmount" : 82.0
}

Operazioni con gli array.

Quando si desidera lavorare con le voci di dati negli array, è necessario innanzitutto srotolare l'array. L'operazione di svolgimento crea un documento per ogni voce nell'array. Quando hai molti documenti con array di grandi dimensioni, vedrai un'esplosione nel numero di documenti.

{ "_id" : 1, "item" : "myItem1", sizes: [ "S", "M", "L"] }
{ "_id" : 2, "item" : "myItem2", sizes: [ "XS", "M", "XL"] }
    
db.inventory.aggregate( [ { $unwind : "$sizes" }] )

Un avviso importante è che quando un documento non contiene la matrice verrà perso. Da mongo 3.2 e versioni successive è disponibile un'opzione di unwinding "preserveNullAndEmptyArrays". Questa opzione assicura che il documento venga conservato quando manca la matrice.

{ "_id" : 1, "item" : "myItem1", sizes: [ "S", "M", "L"] }
{ "_id" : 2, "item" : "myItem2", sizes: [ "XS", "M", "XL"] }
{ "_id" : 3, "item" : "myItem3" }
    
db.inventory.aggregate( [ { $unwind : { path: "$sizes", includeArrayIndex: "arrayIndex" } }] )

Incontro

Come scrivere una query per ottenere tutti i reparti in cui l'età media dei dipendenti che effettua meno di $ 70000 è maggiore o uguale a 35?

Per questo è necessario scrivere una query per abbinare i dipendenti con uno stipendio inferiore o uguale a $ 70000. Quindi aggiungere la fase di aggregazione per raggruppare i dipendenti dal reparto. Quindi aggiungi un accumulatore con un campo chiamato ad esempio average_age per trovare l'età media per dipartimento usando l'accumulatore $ avg e sotto la partita $ esistente e gli aggregati $ gruppo aggiungi un altro aggregato $ match in modo che stiamo recuperando solo i risultati con un average_age che è più grande o uguale a 35.

db.employees.aggregate([
  {"$match": {"salary": {"$lte": 70000}}},
  {"$group": {"_id": "$dept",
              "average_age": {"$avg": "$age"}
             }
  },
  {"$match": {"average_age": {"$gte": 35}}}
])

Il risultato è:

{
  "_id": "IT",
  "average_age": 31
}
{
  "_id": "Customer Service",
  "average_age": 34.5
}
{
  "_id": "Finance",
  "average_age": 32.5
}

Rimuovi documenti che hanno un campo duplicato in una raccolta (deduplica)

Si noti che l'opzione allowDiskUse: true è facoltativa, ma aiuterà a mitigare i problemi di memoria insufficiente in quanto questa aggregazione può essere un'operazione di memoria se la dimensione della raccolta è elevata, quindi consiglio di utilizzarla sempre.

var duplicates = [];

db.transactions.aggregate([
 { $group: { 
   _id: { cr_dr: "$cr_dr"},
   dups: { "$addToSet": "$_id" }, 
   count: { "$sum": 1 } 
 }
}, 
{ $match: { 
  count: { "$gt": 1 }   
}}
],allowDiskUse: true}
)              
.result          
.forEach(function(doc) {
  doc.dups.shift();   
  doc.dups.forEach( function(dupId){ 
    duplicates.push(dupId); 
  }
)    
})
// printjson(duplicates);     

// Remove all duplicates in one go    
db.transactions.remove({_id:{$in:duplicates}})


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow