von Marc-David Militz
Forum: MongoDB Theorie
{
"title" : "mein erster post",
"author" : "Marc",
"likes" : 5
},
{
"title" : "mein zweiter post",
"author" : "Marc",
"likes" : 2
},
{
"title" : "hello world",
"author" : "David",
"likes" : 3
}
... und wir möchten die Anzahl der Likes für jeden Autor haben ...
db.posts.aggregate([
{$group: {_id: "$author", total_likes: { $sum: "$likes"}}}
])
... wir bekommen folgendes Ergebnis ...
{
"_id" : "David",
"total_likes" : 3
},
{
"_id" : "Marc",
"total_likes" : 7
}
db.posts.aggregate([
{$match: { author: "David"}},
{$group: {_id: "$author", total_likes: { $sum: "$likes"}}}
])
Das Ergebnis hierfür sieht folgendermassen aus
{
"_id" : "David",
"total_likes" : 3
}
Beachte: die "aggregate()" Methode bekommt ein Array von Ausdrücken. Jeder dieser Ausdrücke stellt eine "Stage" dar. Die erste Stage benutzt "$match" um die Dokumente nach dem Namen "David" zu filtern. Die zweite Stage nutzt "$group" um das Ergebnis der ersten Stage zu nehmen und dieses zu anhand des Autors zu gruppieren. Der Akkumulator "$sum" wird verwendet um das Ergebnisfeld "total_likes" für das berechnete Ergebnis zu erzeugen. Wichtig ist dabei zu beachten das die Reihenfolge von Bedeutung ist. Jede Stage ist eine In-Memory Verarbeitung der Dokumente und ist „stateless“. Jede Stage referenziert lediglich das Ergebnis, das von der vorhergehenden Stage erzeugt wurde.
{ $sort: { likes : -1 } },
{ $match: { author: 'Marc' } }
... wird diese Abfrage ...
{ $match: { author: 'Marc' } },
{ $sort: { likes : -1 } }
Das macht Sinn, denn "$match" filtert die Collection bevor "$sort" ausgeführt wird. Das erhöht die Performance, da die Sortierung lediglich auf die gefilterten Dokumente angewendet werden muß. Die Optimierungen sind teilweise spezifisch für die verwendete MongoDB Version und werden automatisch angewendet. Mit der "explain" Option kann man sich ansehen ob der Optimizer die Abfrage "unter der Haube" geändert hat.
BEACHTE: Es gibt "Blocking" und "Non-Blocking" Stages. "$sort" ist eine Blocking-Stage. d.h. die nächste Stage kann erst ausgeführt werden, wenn das Zwischenergebnis gebildet und wurde. "$match" ist eine Non-Blocking-Stage, d.h. die gefilterten Dokumente können bereits in der nächsten Stage weiterverarbeitet werden, bevor alle Dokumente die Stage durchlaufen haben. Bei Aggregationen mit vielen Stufen oder beim Verarbeiten von großen Datenmengen kann es daher Perfomancevorteile bringen, Blocking-Stages möglichst weit an das Ende der Pipeline zu setzen.
Die weiteren möglichen Stages werden in der offiziellen MongoDB Dokumentation erläutert. Diese werden auch mit jeder Version erweitert.
https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/