33 Aggregation

Aggregation in MongoDB ermöglicht die Durchführung komplexer Auswertungen und Analysen auf den in einer Datenbank gespeicherten Dokumenten. Statt einzelne Dokumente direkt auszugeben, können im Aggregationsprozess Teilergebnisse berechnet, gefiltert, gruppiert und durch verschiedene Transformationen verändert werden. Dies erleichtert es, aussagekräftige Reports, Statistiken und Analysen direkt innerhalb der Datenbank zu erzeugen, ohne die Daten erst zur weiteren Verarbeitung in externe Systeme übertragen zu müssen.

33.1 Grundlagen

Die Aggregation in MongoDB basiert auf Pipelines, die aus einer Folge von Stages aufgebaut sind. Jede Stage erhält den Output der vorhergehenden Stage als Input, transformiert die Daten gemäß der darin definierten Operatoren und gibt das Ergebnis an die nächste Stage weiter. Dadurch entsteht eine flexible, erweiterbare und modular aufgebaute Verarbeitungskette.

Wichtige Konzepte: - Pipeline: Eine Sequenz von Verarbeitungsschritten (Stages). - Stage: Ein Verarbeitungsschritt, der bestimmte Operationen auf dem Dokumentstrom ausführt. - Operatoren: Spezielle Anweisungen, die innerhalb einer Stage verwendet werden, um Filter-, Gruppierungs-, Projektions- oder andere Transformationslogiken umzusetzen.

33.2 Pipelines und Stages

Eine Aggregations-Pipeline wird durch ein Array von Stages definiert. Jede Stage beginnt typischerweise mit einem Operator wie $match, $group, $project oder $sort. Die Reihenfolge der Stages ist entscheidend für das Endergebnis, da sich die Verarbeitungen voneinander ableiten.

Beispiele für typische Stages: - $match: Filtert Dokumente basierend auf bestimmten Kriterien, ähnlich wie bei einer normalen Query. - $project: Selektiert und transformiert Felder, um nur noch relevante Informationen im Datenstrom zu behalten oder neue Felder auf Basis existierender Werte abzuleiten. - $group: Fasst Dokumente zu Gruppen zusammen, basierend auf Schlüsselwerten und berechnet aggregierte Werte wie Summen, Durchschnitte oder Counts. - $sort: Sortiert die Dokumente nach bestimmten Feldern. - $limit und $skip: Begrenzen oder überspringen eine festgelegte Anzahl von Dokumenten innerhalb der Pipeline.

33.3 Aggregationsoperatoren

Innerhalb einer Stage, vor allem in $group und $project, kommen verschiedene Operatoren zum Einsatz, um Berechnungen durchzuführen oder Felder neu zu definieren. Wichtige Operatoren sind: - Mathematische Operatoren wie $sum, $avg, $min, $max. - String-Operatoren wie $concat, $substr oder $toLower. - Array-Operatoren wie $push, $addToSet oder $size. - Logische Operatoren wie $and, $or, $not. - Konditionale Operatoren wie $cond, um abhängig von Bedingungen unterschiedliche Werte zu erzeugen.

33.4 Beispiele

33.4.1 Summenberechnung

Um den Gesamtumsatz aus einer Sammlung von Bestellungen zu ermitteln, kann eine Pipeline mit $group und $sum verwendet werden. Angenommen, die Dokumente enthalten ein Feld amount mit dem jeweiligen Bestellwert. Durch Gruppierung aller Dokumente ohne einen gruppierenden Schlüssel (oder mit einem konstanten Ausdruck) kann ein Gesamtwert berechnet werden.

db.orders.aggregate([
  { $group: { _id: null, totalAmount: { $sum: "$amount" } } }
])

Diese Pipeline führt dazu, dass ein einzelnes Resultat zurückgegeben wird, welches im Feld totalAmount die Summe aller amount-Felder enthält.

33.4.2 Daten anreichern

Mit $lookup können Daten aus einer anderen Collection eingebunden werden, um zum Beispiel zusätzliche Informationen zu einzelnen Einträgen zu ergänzen. Dies ermöglicht join-ähnliche Operationen innerhalb von MongoDB.

db.orders.aggregate([
  {
    $lookup: {
      from: "customers",
      localField: "customerId",
      foreignField: "_id",
      as: "customerInfo"
    }
  }
])

Dadurch werden für jede Bestellung die passenden Kundendaten aus der customers Collection in das Feld customerInfo eingefügt.

33.4.3 Komplexere Datenumwandlungen

Mit $project lassen sich Felder transformieren, um etwa Felder umzubenennen, Felder auszublenden oder neue Felder auf Basis existierender Daten zu berechnen.

db.orders.aggregate([
  {
    $project: {
      _id: 0,
      orderId: "$_id",
      orderTotal: "$amount",
      month: { $month: "$orderDate" }
    }
  }
])

In diesem Beispiel werden vorhandene Felder umbenannt und ein neues Feld month auf Basis des Datumsfelds orderDate erzeugt.

33.5 Indexnutzung und Performance

Aggregation kann von Indexen profitieren, insbesondere wenn $match und $sort früh in der Pipeline stehen und Abfragen filtern oder sortieren, die von einem Index unterstützt werden. Durch die geschickte Anordnung von Stages kann so die Performance der Aggregation erheblich verbessert werden.

Empfehlungen zur Performance: - $match möglichst früh verwenden, um die Datenmenge rasch einzuschränken. - $sort möglichst früh und auf Felder anwenden, die indexiert sind. - Komplexe Berechnungen und Transformationen erst nach effizienten Filter- und Sortiervorgängen durchführen, um nur noch relevante Datenmengen verarbeiten zu müssen.

33.6 Skalierung im Sharded Cluster

In einem Sharded Cluster werden Aggregationspipelines verteilt ausgeführt. Jede Shard führt die Pipeline-Stages auf die lokalen Daten aus und liefert Teilergebnisse an den mongos, der dann weitere Stages anwendet. Werden Shard Keys und Indexe sinnvoll gewählt, können Aggregationsprozesse effizient über mehrere Shards parallelisiert werden.