Aggregation ermöglicht es, komplexe Analysen und Transformationen
direkt innerhalb der Datenbank durchzuführen. Im Folgenden werden
verschiedene Beispiele und Anwendungsfälle aufgezeigt, um die
Möglichkeiten der Aggregation praxisnah zu veranschaulichen. Dabei
kommen unterschiedliche Stages, Operatoren sowie das Einbinden externer
Datenquellen mittels $lookup zum Einsatz.
Ein grundlegendes Szenario ist die Vorauswahl relevanter Dokumente
aus einer Collection. Mit $match werden Dokumente
gefiltert, während $sort für die Sortierung sorgt.
db.products.aggregate([
{ $match: { category: "electronics", price: { $lt: 500 } } },
{ $sort: { price: 1 } }
])Diese Pipeline gibt alle Produkte der Kategorie “electronics” aus, deren Preis unter 500 liegt, sortiert nach aufsteigendem Preis.
Mit $group lassen sich Dokumente nach bestimmten Feldern
gruppieren und aggregierte Kennzahlen berechnen. Hier wird die
durchschnittliche Bewertung (rating) pro Kategorie
bestimmt:
db.reviews.aggregate([
{ $group: { _id: "$category", avgRating: { $avg: "$rating" } } },
{ $sort: { avgRating: -1 } }
])Das Ergebnis enthält pro Kategorie den durchschnittlichen Bewertungswert, absteigend sortiert.
$project ermöglicht es, Felder auszuwählen, umzubenennen
oder neue Felder auf Basis bestehender Informationen zu erzeugen. Hier
werden aus einer Bestellung die wesentlichen Daten extrahiert, während
interne Systemfelder ausgeblendet werden:
db.orders.aggregate([
{
$project: {
_id: 0,
orderId: "$_id",
itemCount: { $size: "$items" },
totalValue: { $sum: "$items.price" }
}
}
])Es entsteht ein Ergebnis mit orderId, der Anzahl der
enthaltenen Artikel (itemCount) und einem berechneten
Gesamtwert (totalValue).
Pipelines lassen sich aus beliebig vielen Stages zusammensetzen. So kann etwa zuerst gefiltert, dann gruppiert und anschließend ein Durchschnitt berechnet werden. Hier werden zunächst alle Transaktionen aus dem aktuellen Monat selektiert, dann die Summe pro Kunde gebildet und abschließend nach den höchsten Umsätzen sortiert:
db.transactions.aggregate([
{ $match: { month: 8 } },
{ $group: { _id: "$customerId", totalSpend: { $sum: "$amount" } } },
{ $sort: { totalSpend: -1 } }
])$lookupDas $lookup-Stage ermöglicht ein Join-ähnliches
Verhalten. Daten aus einer anderen Collection können eingebunden werden,
um weitere Informationen zu ergänzen. Beispiel: Angenommen, wir haben
eine orders-Collection mit Kunden-IDs, aber benötigen
Kundeninformationen aus der customers-Collection:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerInfo"
}
}
])Das Ergebnis enthält für jede Bestellung ein Feld
customerInfo, das die passenden Kundendaten aus der
customers-Collection eingebunden hat. So lässt sich
beispielsweise im nächsten Schritt problemlos auf den Namen oder die
Adresse des Kunden zugreifen, ohne selbst einen weiteren Query ausführen
zu müssen.
$lookupEs ist auch möglich, $lookup mehrfach einzusetzen, um
Informationen aus mehreren Collections einzubinden. Hier werden zu
Bestellungen sowohl Kundendaten als auch Artikeldaten ergänzt:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerInfo"
}
},
{
$lookup: {
from: "products",
localField: "items.productId",
foreignField: "_id",
as: "productDetails"
}
}
])Damit stehen nun sowohl die Kundendetails als auch die Produktinformationen im selben Dokument für weitere Auswertungen zur Verfügung.
$lookupNach dem Einbinden externer Daten lassen sich diese natürlich weiter
verarbeiten, filtern oder zusammenfassen. Hier ein Beispiel, bei dem
nach dem $lookup nur bestimmte Felder aus den verbundenen
Datensätzen projiziert werden:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerInfo"
}
},
{
$project: {
orderId: "$_id",
customerName: { $arrayElemAt: ["$customerInfo.name", 0] },
orderValue: { $sum: "$items.price" }
}
}
])Aus dem eingebundenen customerInfo-Array wird der erste
Eintrag extrahiert, um den Kundennamen direkt im Ergebnis anzuzeigen.
Gleichzeitig wird der Gesamtbestellwert berechnet und das Feld
_id in orderId umbenannt.
Mit Operatoren wie $cond, $ifNull oder
logischen Operatoren lassen sich komplexe Bedingungen definieren. Hier
ein Beispiel, bei dem für jeden Datensatz geprüft wird, ob er ein
bestimmtes Feld enthält und andernfalls ein Standardwert zugewiesen
wird:
db.inventory.aggregate([
{
$project: {
_id: 0,
item: 1,
price: {
$cond: {
if: { $gte: ["$price", 0] },
then: "$price",
else: 0
}
}
}
}
])Sollte kein Preis gesetzt sein, wird der Wert automatisch auf 0 gesetzt.