MongoDB
Aggregazione
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}})