- 1 Section
- 10 Lessons
- unbegrenzt
- NoSQL – MongoDB, Redis & Grundlagen10
MongoDB Aggregation Pipeline
Mit den CRUD-Operationen aus Lektion 5 kannst du Daten einfügen, lesen, ändern, löschen. Was du nicht kannst: Daten gruppieren, aggregieren, transformieren. Genau dafür gibt es die Aggregation Pipeline – MongoDBs Antwort auf SQL-Konstrukte wie GROUP BY, SUM/AVG/COUNT und JOINs.
Die Idee ist elegant und in jeder modernen Datenverarbeitung wiederzufinden (Unix-Pipes, Spark, Pandas): Daten fließen durch eine Reihe von Stages (Pipeline-Stufen). Jede Stage nimmt Dokumente entgegen, transformiert sie nach einer bestimmten Regel und reicht sie an die nächste Stage weiter. Am Ende kommt das gewünschte Ergebnis raus.
1) Das Pipeline-Konzept
Eine Aggregation Pipeline ist ein Array von Stages. Jede Stage beginnt mit einem Operator-Namen (z.B. $match, $group), gefolgt von Parametern. Das Ergebnis einer Stage ist die Eingabe der nächsten:
// Stage 1: Filter nach Datum
{ $match: { datum: { $gte: ISODate("2024-01-01") } } },
// Stage 2: Gruppieren nach Kunde, Umsätze summieren
{ $group: { _id: "$kunde_id", umsatz: { $sum: "$summe" } } },
// Stage 3: Absteigend sortieren
{ $sort: { umsatz: -1 } },
// Stage 4: Top 10 ausgeben
{ $limit: 10 }
]);
Diese Pipeline beantwortet: „Welche zehn Kunden hatten 2024 den höchsten Gesamtumsatz?". In SQL wäre das ein einziger Befehl mit WHERE, GROUP BY, ORDER BY, LIMIT. In MongoDB ist es eine Pipeline – konzeptionell sehr ähnlich, syntaktisch anders.
2) Die wichtigsten Stages
Es gibt rund 25 Stage-Typen, aber sechs davon machen 90% der Arbeit. Klick durch um zu sehen was sie tun:
$match sollte möglichst früh stehen – je weniger Dokumente die folgenden Stages verarbeiten müssen, desto schneller läuft die ganze Pipeline. $match nach einem $group ist langsamer als davor. Der Query-Optimizer von MongoDB versucht solche Reihenfolge-Optimierungen automatisch zu machen, aber gute Pipeline-Reihenfolge ist trotzdem dein Job.3) SQL ↔ Aggregation Pipeline
Wenn du SQL kennst, hilft eine direkte Übersetzung beim Lernen. Hier dieselbe Abfrage in beiden Sprachen:
SUM(summe) AS umsatz,
COUNT(*) AS bestellungen
FROM bestellungen
WHERE datum >= '2024-01-01'
GROUP BY stadt
ORDER BY umsatz DESC
LIMIT 5;
{ $match: {
datum: { $gte: ISODate("2024-01-01") } } },
{ $group: {
_id: "$stadt",
umsatz: { $sum: "$summe" },
bestellungen: { $sum: 1 } } },
{ $sort: { umsatz: -1 } },
{ $limit: 5 }
]);
_id als Gruppen-Schlüssel, SUM/COUNT zu $sum, ORDER BY zu $sort, LIMIT bleibt $limit. Felder werden mit Dollar-Präfix referenziert ("$stadt" meint „den Wert des Felds stadt"), was am Anfang gewöhnungsbedürftig ist.4) $group im Detail
Die $group-Stage ist der mächtigste und gleichzeitig komplexeste Operator. Sie gruppiert Dokumente nach einem Schlüssel und erlaubt Aggregationen pro Gruppe. Das Feld _id in der Stage definiert den Gruppen-Schlüssel; alle anderen Felder berechnen aggregierte Werte pro Gruppe:
{ $group: {
_id: "$stadt",
anzahl: { $sum: 1 }, // COUNT(*)
umsatz: { $sum: "$summe" }, // SUM(summe)
durchschn: { $avg: "$summe" }, // AVG(summe)
max_betrag: { $max: "$summe" },
min_betrag: { $min: "$summe" },
alle_kunden: { $addToSet: "$kunde_id" } // distinct list
} }
]);
Spezialfall: wenn _id: null gesetzt wird, wird über die gesamte Collection aggregiert – das Äquivalent zu SELECT SUM(…) FROM … ohne GROUP BY. Bei mehreren Gruppen-Feldern setzt man ein Objekt: _id: { stadt: "$stadt", monat: "$monat" } – das ist GROUP BY mit zwei Feldern.
5) $lookup – der JOIN für MongoDB
Seit MongoDB 3.2 gibt es $lookup, eine JOIN-ähnliche Operation. Damit kannst du Daten aus anderen Collections in deine Pipeline ziehen – nützlich bei referenzierten Datenmodellen. Achtung: $lookup ist teurer als ein klassischer SQL-JOIN, weil keine Indizes auf der „rechten" Collection automatisch genutzt werden.
{ $lookup: {
from: "kunden", // die "rechte" Collection
localField: "kunde_id", // Feld in bestellungen
foreignField: "_id", // Feld in kunden
as: "kunde_info" // Name des neuen Felds (Array)
} }
]);
Das Ergebnis: jedes Bestellungs-Dokument bekommt ein neues Feld kunde_info mit den passenden Kunden-Dokumenten als Array. Wenn du genau einen Treffer erwartest (1:1-Beziehung), folgt meist ein $unwind, um aus dem Array ein einzelnes Sub-Dokument zu machen.
Praxis-Tipp: bei häufigen $lookup-Operationen ist das oft ein Zeichen, dass du dein Datenmodell überdenken solltest. Wenn zwei Collections immer zusammen gelesen werden, ist eine Embedded-Struktur oft schneller.
6) Pipeline live bauen
Schalte Stages an und sieh wie sich das Ergebnis verändert. Test-Daten sind ein Mini-Datensatz mit Bestellungen:
Aktiviere/deaktiviere Stages und sieh wie die Ergebnisse durch die Pipeline fließen:
Ergebnis nach Pipeline:
$sort nach $limit ist nicht dasselbe wie $limit nach $sort – ersteres sortiert nur die 3 zufällig genommenen Dokumente, letzteres die ganze Liste vor dem Begrenzen. Bei großen Datenmengen lohnt sich dieser Unterschied massiv (Performance + Korrektheit).7) Weitere häufig genutzte Stages
Neben den großen sechs gibt es eine Handvoll weiterer Stages, die du häufig brauchst:
- $unwind: löst Arrays auf – aus einem Dokument mit einem Array von n Elementen werden n Dokumente, jeweils mit einem Element. Klassisch nach
$lookup. - $addFields / $set: fügt neue Felder hinzu ohne andere zu entfernen (im Gegensatz zu
$project, das alle nicht genannten verwirft). - $count: zählt die Dokumente, die bis zu diesem Punkt der Pipeline durchgekommen sind.
- $facet: führt mehrere Sub-Pipelines parallel aus – sehr nützlich für Dashboards mit mehreren Statistiken auf einmal.
- $out / $merge: schreibt das Ergebnis in eine Collection – nützlich für vorberechnete Reports.
Eine vollständige Auflistung gibt's in der MongoDB-Doku unter „Aggregation Pipeline Stages". Für die IHK-Prüfung reicht es zu wissen, was die ersten sechs tun.
8) Performance-Tipps
Aggregationen können bei großen Datenmengen sehr teuer werden. Drei Faustregeln, die das meiste herausholen:
- Filtern früh:
$matchals erste Stage. Reduziert die Datenmenge für alle folgenden Stages. Idealerweise nutzt der Filter einen Index. - $project oder $unset früh: wenn du nur zwei Felder brauchst, wirf den Rest gleich am Anfang weg. Spart Speicher und Übertragung.
- $limit nach $sort, wenn möglich: bei sortierten Top-N-Anfragen kann MongoDB clever optimieren wenn der Sortier-Index genutzt wird.
Mit db.collection.aggregate(pipeline).explain() bekommst du den Ausführungsplan – analog zum EXPLAIN in SQL. Da siehst du, ob Indizes genutzt werden und wo Bottlenecks sind.
Zusammenfassung
Die Aggregation Pipeline ist MongoDBs Antwort auf komplexere Datenanalyse-Abfragen. Daten fließen durch eine Reihe von Stages, jede transformiert sie nach einer Regel. Wichtigste Stages: $match (filtern, wie WHERE), $project (Felder auswählen/umformen, wie SELECT), $group (gruppieren + aggregieren, wie GROUP BY mit SUM/AVG/COUNT), $sort (sortieren, wie ORDER BY), $limit (begrenzen), $lookup (Join-ähnlich). Felder werden mit Dollar-Präfix referenziert: "$stadt" = „Wert des stadt-Felds". Performance-Regeln: filtern früh, Felder früh reduzieren, Indizes nutzen. Ergebnis-Check mit .explain(). Verglichen mit reinen CRUD-Operationen deutlich mächtiger, aber auch teurer – nur einsetzen wo nötig.
