MongoDB
aggregation
Sök…
Introduktion
Aggregations
bearbetar dataregister och returnerar beräknade resultat. Aggregationsoperationsgruppvärden från flera dokument tillsammans och kan utföra en mängd olika operationer på den grupperade datan för att returnera ett enda resultat. MongoDB tillhandahåller tre sätt att utföra aggregering: aggregeringsrörledningen, kartminskningsfunktionen och aggregeringsmetoder med en enda syfte.
Från Mongo-manualen https://docs.mongodb.com/manual/aggregation/
Syntax
- db.collection.aggregate (pipeline, optioner)
parametrar
Parameter | detaljer |
---|---|
rörledning | array (En sekvens av datainsamlingsoperationer eller -steg) |
alternativ | dokument (valfritt, endast tillgängligt om pipeline finns som en matris) |
Anmärkningar
Aggregationsramverk i MongoDB används för att uppnå gemensam GROUP BY
funktion i SQL.
Tänk på följande infogningar i samlade namngivna transactions
för varje exempel.
> 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});
Räkna
Hur får du antalet debiterings- och kredittransaktioner? Ett sätt att göra det är att använda funktionen count()
enligt nedan.
> db.transactions.count({cr_dr : "D"});
eller
> db.transactions.find({cr_dr : "D"}).length();
Men tänk om du inte känner till de möjliga värdena på cr_dr
förhand. Här kommer aggregeringsramen att spela. Se den sammanlagda frågan nedan.
> 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}
}
}
]
);
Och resultatet är
{
"_id" : "C",
"count" : 3
}
{
"_id" : "D",
"count" : 5
}
Summa
Hur får man summeringen av amount
? Se den sammanlagda frågan nedan.
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr',
count : {$sum : 1}, //counts the number
totalAmount : {$sum : '$amount'} //sums the amount
}
}
]
);
Och resultatet är
{
"_id" : "C",
"count" : 3.0,
"totalAmount" : 120.0
}
{
"_id" : "D",
"count" : 5.0,
"totalAmount" : 410.0
}
En annan version som summerar amount
och fee
.
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr',
count : {$sum : 1},
totalAmount : {$sum : { $sum : ['$amount', '$fee']}}
}
}
]
);
Och resultatet är
{
"_id" : "C",
"count" : 3.0,
"totalAmount" : 128.0
}
{
"_id" : "D",
"count" : 5.0,
"totalAmount" : 422.0
}
Medel
Hur får man det genomsnittliga beloppet för debet- och kredittransaktioner?
> 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
}
}
]
)
Resultatet är
{
"_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
}
Operationer med matriser.
När du vill arbeta med datainmatningarna i matriser måste du först lossa matrisen. Avrullningsfunktionen skapar ett dokument för varje post i matrisen. När du har många dokument med stora matriser ser du en explosion i antal dokument.
{ "_id" : 1, "item" : "myItem1", sizes: [ "S", "M", "L"] }
{ "_id" : 2, "item" : "myItem2", sizes: [ "XS", "M", "XL"] }
db.inventory.aggregate( [ { $unwind : "$sizes" }] )
Ett viktigt meddelande är att när ett dokument inte innehåller matrisen kommer det att gå förlorat. Från mongo 3.2 och uppåt finns ett avkopplingsalternativ "preserveNullAndEmptyArrays" till. Det här alternativet ser till att dokumentet bevaras när matrisen saknas.
{ "_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" } }] )
Match
Hur skriver man en fråga för att få alla avdelningar där medelåldern för anställda som gör mindre än eller $ 70000 är större än eller lika med 35?
För att vi måste skriva en fråga för att matcha anställda som har en lön som är mindre än eller lika med $ 70000. Lägg sedan till det sammanlagda skedet för att gruppera de anställda vid avdelningen. Lägg sedan till en ackumulator med ett fält som heter t.ex. gemiddelde_age för att hitta genomsnittsåldern per avdelning med hjälp av $ avg-ackumulatorn och under den befintliga $ -matchen och $ -gruppsaggregat lägger till ytterligare $ matchningsaggregat så att vi bara hämtar resultat med en genomsnittlig_age som är greather än eller lika med 35.
db.employees.aggregate([
{"$match": {"salary": {"$lte": 70000}}},
{"$group": {"_id": "$dept",
"average_age": {"$avg": "$age"}
}
},
{"$match": {"average_age": {"$gte": 35}}}
])
Resultatet är:
{
"_id": "IT",
"average_age": 31
}
{
"_id": "Customer Service",
"average_age": 34.5
}
{
"_id": "Finance",
"average_age": 32.5
}
Ta bort dokument som har ett duplikatfält i en samling (dedupe)
Observera att tillvalet allowDiskUse: true är valfritt men kommer att hjälpa till att minska problem i minnet eftersom denna aggregering kan vara en minnesintensiv operation om din samlingsstorlek är stor - så jag rekommenderar att du alltid använder den.
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}})