MongoDB Aggregation Pipeline

6 Kern-Stages
Die wichtigsten MongoDB Aggregation Pipeline Stages: $match · $group · $project · $sort · $lookup · $unwind Die Aggregation Pipeline ist MongoDBs leistungsstarkes Framework für Datenanalysen und Transformationen. Sie durchläuft Dokumente Schritt für Schritt und ermöglicht komplexe Abfragen, Gruppierungen und Joins.

$match – Dokumente filtern

{ $match: { feld: wert, ... } }
// Nur aktive Benutzer { $match: { status: "active" } } // Alter zwischen 18 und 65 { $match: { age: { $gte: 18, $lte: 65 } } }

$match filtert Dokumente ähnlich wie find() in der Aggregation Pipeline. Es sollte möglichst früh in der Pipeline stehen, um die Datenmenge zu reduzieren.

Beispiele
// Benutzer mit Alter über 18
{ $match: { age: { $gt: 18 } } }
// Bestellungen mit Betrag > 100
{ $match: { total: { $gt: 100 } } }
// Komplexe Bedingung mit $and
{ $match: {
$and: [
{ status: "active" },
{ createdAt: { $gte: ISODate("2024-01-01") } }
]
} }
Tipp: Platzieren Sie $match so früh wie möglich in der Pipeline, um die Anzahl der zu verarbeitenden Dokumente zu reduzieren – das verbessert die Performance erheblich.

$group – Dokumente gruppieren

{ $group: { _id: "$feld", ... } }
// Summe pro Kategorie { $group: { _id: "$category", total: { $sum: "$amount" } } }

$group gruppiert Dokumente nach einem Schlüssel (_id) und berechnet Aggregationen wie Summe, Durchschnitt, Minimum, Maximum oder zählt Dokumente.

Wichtige Aggregationsoperatoren

Operator Beschreibung Beispiel
$sum Summiert Werte { $sum: "$amount" }
$avg Durchschnitt berechnen { $avg: "$price" }
$min Minimalwert { $min: "$age" }
$max Maximalwert { $max: "$age" }
$count Anzahl Dokumente { $sum: 1 }
$push Array von Werten { $push: "$name" }
$addToSet Eindeutige Werte { $addToSet: "$category" }
Beispiele
// Durchschnittsalter pro Kategorie
{ $group: {
_id: "$category",
avgAge: { $avg: "$age" },
count: { $sum: 1 }
} }
// Top 3 Kategorien mit den meisten Bestellungen
{ $group: {
_id: "$category",
count: { $sum: 1 }
} }
// Alle Produktnamen pro Kategorie
{ $group: {
_id: "$category",
products: { $push: "$name" }
} }
Tipp: $group mit $push ist nützlich, um Arrays von Werten pro Gruppe zu erstellen – z.B. alle Produktnamen pro Kategorie.

$project – Felder auswählen / umformen

{ $project: { feld: 1, ... } }
// Nur Name und Preis { $project: { name: 1, price: 1 } } // Berechnetes Feld { $project: { fullName: { $concat: ["$firstName", " ", "$lastName"] } } }

$project wählt Felder aus, schließt sie aus oder erstellt neue berechnete Felder. Es formt die Dokumente für die weitere Verarbeitung um.

Beispiele
// Felder einschließen
{ $project: { name: 1, email: 1, _id: 0 } }
// Berechnetes Feld (Vollständiger Name)
{ $project: {
fullName: { $concat: ["$firstName", " ", "$lastName"] },
age: 1
} }
// Preise inklusive Mehrwertsteuer
{ $project: {
name: 1,
price: 1,
priceWithTax: { $multiply: ["$price", 1.19] }
} }
// Bedingte Felder mit $cond
{ $project: {
name: 1,
status: {
$cond: {
if: { $gte: ["$age", 18] },
then: "adult",
else: "minor"
}
}
} }
Tipp: Verwenden Sie $project am Ende der Pipeline, um die Ausgabe zu formatieren. In der Mitte der Pipeline kann es helfen, die Dokumentstruktur für nachfolgende Stages anzupassen.

$sort & $limit – Sortieren und begrenzen

{ $sort: { feld: 1|-1 } } · { $limit: n }
// Sortieren und Top 5 { $sort: { price: -1 } } { $limit: 5 }

$sort sortiert Dokumente (1 = aufsteigend, -1 = absteigend). $limit begrenzt die Anzahl der Dokumente. Werden oft nach $group verwendet, um Top-Listen zu erstellen.

Beispiele
// 10 teuerste Produkte
{ $sort: { price: -1 } },
{ $limit: 10 }
// Top 3 Kategorien mit den meisten Bestellungen
{ $group: {
_id: "$category",
count: { $sum: 1 }
} },
{ $sort: { count: -1 } },
{ $limit: 3 }
// Nach mehreren Feldern sortieren
{ $sort: {
category: 1,
price: -1
} }
Tipp: Platzieren Sie $sort so früh wie möglich in der Pipeline, wenn Sie Indizes nutzen können. $limit nach $sort reduziert die Datenmenge für nachfolgende Stages.

$lookup – JOIN zwischen Collections

{ $lookup: { from: "collection", ... } }
// JOIN: Bestellungen mit Benutzerdaten { $lookup: { from: "users", localField: "userId", foreignField: "_id", as: "user" } }

$lookup führt eine Left Outer Join zwischen der aktuellen Collection und einer anderen Collection durch. Die Ergebnisse werden als Array in das angegebene Feld (as) eingefügt.

Beispiele
// Bestellungen mit Benutzerdaten
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
} }
// Mit $unwind: Benutzer als Objekt statt Array
{ $lookup: { from: "users", localField: "userId", foreignField: "_id", as: "user" } },
{ $unwind: "$user" }
// Mehrere Joins (z.B. Produkt + Kategorie)
{ $lookup: { from: "categories", localField: "categoryId", foreignField: "_id", as: "category" } },
{ $lookup: { from: "suppliers", localField: "supplierId", foreignField: "_id", as: "supplier" } }
Tipp: $lookup erzeugt ein Array. Mit $unwind können Sie das Array in einzelne Dokumente aufteilen. Für effiziente Joins sollten Sie Indizes auf foreignField anlegen.

$unwind – Arrays auflösen

{ $unwind: { path: "$array" } }
// Ein Dokument pro Array-Element { $unwind: "$items" } // Mit preserveNullAndEmptyArrays { $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }

$unwind dekonstruiert ein Array-Feld: Für jedes Element des Arrays wird ein separates Dokument erzeugt. Nützlich für die Verarbeitung von Arrays in der Aggregation Pipeline.

Beispiele
// Bestellpositionen auflösen
{ $unwind: "$orderItems" }
// Mit preserveNullAndEmptyArrays
{ $unwind: {
path: "$tags",
preserveNullAndEmptyArrays: true
} }
// Für $lookup mit Arrays
{ $lookup: { from: "products", localField: "productIds", foreignField: "_id", as: "products" } },
{ $unwind: "$products" }
// Kombiniert mit $group für Aggregation
{ $unwind: "$items" },
{ $group: {
_id: "$items.category",
total: { $sum: "$items.amount" }
} }
Tipp: $unwind kann die Anzahl der Dokumente stark erhöhen. Verwenden Sie preserveNullAndEmptyArrays: true, wenn Sie Dokumente mit leeren Arrays nicht verlieren möchten.

Aggregation Pipeline im Überblick

$match Filtern
WHERE in SQL
$group Gruppieren
GROUP BY + Aggregation
$project Projizieren
SELECT + Ausdrücke
$sort Sortieren
ORDER BY
$lookup JOIN
Verbindung zwischen Collections
$unwind Array auflösen
Ein Dokument pro Array-Element

Quick Summary

$match
Filtern
$group
Gruppieren
$project
Felder auswählen
$sort
Sortieren
$lookup
JOIN
$unwind
Array auflösen
db.orders.aggregate([
{ $match: { total: { $gt: 100 } } },
{ $group: { _id: "$category", total: { $sum: 1 } } },
{ $sort: { total: -1 } },
{ $limit: 5 }
])