MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB-Aggregationen mit Java

1. Übersicht

In diesem Tutorial tauchen wir in das MongoDB-Aggregationsframework unter Verwendung des MongoDB-Java-Treibers ein .

Wir sehen uns zuerst an, was Aggregation konzeptionell bedeutet, und richten dann einen Datensatz ein. Schließlich sehen wir verschiedene Aggregationstechniken in Aktion mit dem Aggregate Builder .

2. Was sind Aggregationen?

Aggregationen werden in MongoDB verwendet, um Daten zu analysieren und aussagekräftige Informationen daraus abzuleiten .

Diese werden normalerweise in verschiedenen Stufen durchgeführt, und die Stufen bilden eine Pipeline – so dass die Ausgabe einer Stufe als Eingabe an die nächste Stufe weitergegeben wird.

Die am häufigsten verwendeten Stufen können wie folgt zusammengefasst werden:

Bühne SQL-Äquivalent Beschreibung
 Projekt SELECT wählt nur die erforderlichen Felder aus, kann auch zum Berechnen und Hinzufügen abgeleiteter Felder zur Sammlung verwendet werden
 Übereinstimmung WO filtert die Sammlung nach festgelegten Kriterien
 Gruppe GRUPPE NACH sammelt Eingaben gemäß den angegebenen Kriterien (z. B. Anzahl, Summe), um ein Dokument für jede unterschiedliche Gruppierung zurückzugeben
 sortieren ORDER BY sortiert die Ergebnisse in aufsteigender oder absteigender Reihenfolge eines bestimmten Felds
 Anzahl COUNT zählt die in der Sammlung enthaltenen Dokumente
 Limit LIMIT beschränkt das Ergebnis auf eine bestimmte Anzahl von Dokumenten, anstatt die gesamte Sammlung zurückzugeben
 aus SELECT INTO NEW_TABLE schreibt das Ergebnis in eine benannte Sammlung; diese Phase ist nur als letzte in einer Pipeline akzeptabel


Das SQL-Äquivalent für jede Aggregationsstufe ist oben angegeben, um uns eine Vorstellung davon zu geben, was die besagte Operation in der SQL-Welt bedeutet.

Wir werden uns in Kürze Java-Codebeispiele für alle diese Phasen ansehen. Aber vorher brauchen wir eine Datenbank.

3. Datenbankeinrichtung

3.1. Datensatz

Die erste und wichtigste Voraussetzung, um etwas über Datenbanken zu lernen, ist der Datensatz selbst!

Für dieses Tutorial verwenden wir einen öffentlich verfügbaren Restful-API-Endpunkt, der umfassende Informationen zu allen Ländern der Welt bereitstellt. Diese API liefert uns viele Datenpunkte für ein Land in einem praktischen JSON-Format . Einige der Felder, die wir in unserer Analyse verwenden, sind:

  • Name – der Name des Landes; zum Beispiel Vereinigte Staaten von Amerika
  • alpha3Code – ein Shortcode für den Ländernamen; zum Beispiel IND (für Indien)
  • Region – die Region, zu der das Land gehört; zum Beispiel Europa
  • Bereich – das geografische Gebiet des Landes
  • Sprachen – Amtssprachen des Landes in einem Array-Format; zum Beispiel Englisch
  • Grenzen – eine Reihe von alpha3Code der Nachbarländer s

Sehen wir uns nun an, wie man diese Daten in eine Sammlung in einer MongoDB-Datenbank umwandelt .

3.2. Importieren in MongoDB

Zuerst müssen wir den API-Endpunkt erreichen, um alle Länder abzurufen, und die Antwort lokal in einer JSON-Datei speichern . Der nächste Schritt besteht darin, es mit mongoimport in MongoDB zu importieren Befehl:

mongoimport.exe --db <db_name> --collection <collection_name> --file <path_to_file> --jsonArray

Ein erfolgreicher Import sollte uns eine Sammlung mit 250 Dokumenten liefern.

4. Aggregationsbeispiele in Java

Nachdem wir nun die Grundlagen abgedeckt haben, lassen Sie uns damit beginnen, einige aussagekräftige Erkenntnisse aus den Daten abzuleiten, die wir für alle Länder haben . Zu diesem Zweck verwenden wir mehrere JUnit-Tests.

Aber bevor wir das tun, müssen wir eine Verbindung zur Datenbank herstellen:

@BeforeClass
public static void setUpDB() throws IOException {
    mongoClient = MongoClients.create();
    database = mongoClient.getDatabase(DATABASE);
    collection = database.getCollection(COLLECTION);
}

In allen folgenden Beispielen werden wir die Aggregate verwenden Hilfsklasse, die vom MongoDB-Java-Treiber bereitgestellt wird.

Zur besseren Lesbarkeit unserer Snippets können wir einen statischen Import hinzufügen:

import static com.mongodb.client.model.Aggregates.*;

4.1. Übereinstimmung und zählen

Beginnen wir zunächst mit etwas Einfachem. Zuvor haben wir angemerkt, dass der Datensatz Informationen zu Sprachen enthält.

Angenommen, wir möchten die Anzahl der Länder in der Welt überprüfen, in denen Englisch eine Amtssprache ist :

@Test
public void givenCountryCollection_whenEnglishSpeakingCountriesCounted_thenNinetyOne() {
    Document englishSpeakingCountries = collection.aggregate(Arrays.asList(
      match(Filters.eq("languages.name", "English")),
      count())).first();
    
    assertEquals(91, englishSpeakingCountries.get("count"));
}

Hier verwenden wir zwei Phasen in unserer Aggregationspipeline:Match und zählen .

Zuerst filtern wir die Sammlung heraus, um nur die Dokumente abzugleichen, die Englisch enthalten in ihren Sprachen Feld. Diese Dokumente kann man sich als temporäre oder Zwischensammlung vorstellen, die die Eingabe für unsere nächste Stufe count. wird Dies zählt die Anzahl der Dokumente in der vorherigen Stufe.

Ein weiterer zu beachtender Punkt in diesem Beispiel ist die Verwendung der Methode first . Da wir wissen, dass die Ausgabe der letzten Stufe, count , wird ein einzelner Datensatz sein, dies ist ein garantierter Weg, um das einzelne resultierende Dokument zu extrahieren.

4.2. Gruppe (mit Summe ) und sortieren

In diesem Beispiel ist unser Ziel, die geografische Region herauszufinden, die die maximale Anzahl an Ländern enthält :

@Test
public void givenCountryCollection_whenCountedRegionWise_thenMaxInAfrica() {
    Document maxCountriedRegion = collection.aggregate(Arrays.asList(
      group("$region", Accumulators.sum("tally", 1)),
      sort(Sorts.descending("tally")))).first();
    
    assertTrue(maxCountriedRegion.containsValue("Africa"));
}

Wie ersichtlich ist, verwenden wir group und sortieren unser Ziel hier zu erreichen .

Zuerst erfassen wir die Anzahl der Länder in jeder Region, indem wir eine Summe akkumulieren ihres Vorkommens in einer Variablen Tally. Dies gibt uns eine Zwischensammlung von Dokumenten, die jeweils zwei Felder enthalten:die Region und die Liste der darin enthaltenen Länder. Dann sortieren wir es in absteigender Reihenfolge und extrahieren das erste Dokument, um uns die Region mit den meisten Ländern zu geben.

4.3. sortieren, begrenzen, und aus

Lassen Sie uns nun sortieren verwenden , begrenzen und aus die sieben größten Länder flächenmäßig zu extrahieren und in eine neue Sammlung zu schreiben :

@Test
public void givenCountryCollection_whenAreaSortedDescending_thenSuccess() {
    collection.aggregate(Arrays.asList(
      sort(Sorts.descending("area")), 
      limit(7),
      out("largest_seven"))).toCollection();

    MongoCollection<Document> largestSeven = database.getCollection("largest_seven");

    assertEquals(7, largestSeven.countDocuments());

    Document usa = largestSeven.find(Filters.eq("alpha3Code", "USA")).first();

    assertNotNull(usa);
}

Hier haben wir zunächst die angegebene Sammlung in absteigender Reihenfolge nach Bereich. sortiert Dann haben wir das Aggregates#limit verwendet Methode, um das Ergebnis auf nur sieben Dokumente zu beschränken. Schließlich haben wir out verwendet Phase, um diese Daten in eine neue Sammlung namens largest_seven zu deserialisieren . Diese Sammlung kann nun wie jede andere verwendet werden – zum Beispiel zum finden wenn es USA. enthält

4.4. Projekt, Gruppe (mit max), Übereinstimmung

Lassen Sie uns in unserem letzten Beispiel etwas kniffligeres versuchen. Sagen wir, wir müssen herausfinden, wie viele Grenzen jedes Land mit anderen teilt und wie viele solche Grenzen maximal sind .

Jetzt haben wir in unserem Datensatz eine Grenze -Feld, das ein Array ist, das alpha3Code auflistet s für alle angrenzenden Länder der Nation, aber es gibt kein Feld, das uns direkt die Zählung gibt. Wir müssen also die Anzahl der borderingCountries ableiten mit Projekt :

@Test
public void givenCountryCollection_whenNeighborsCalculated_thenMaxIsFifteenInChina() {
    Bson borderingCountriesCollection = project(Projections.fields(Projections.excludeId(), 
      Projections.include("name"), Projections.computed("borderingCountries", 
        Projections.computed("$size", "$borders"))));
    
    int maxValue = collection.aggregate(Arrays.asList(borderingCountriesCollection, 
      group(null, Accumulators.max("max", "$borderingCountries"))))
      .first().getInteger("max");

    assertEquals(15, maxValue);

    Document maxNeighboredCountry = collection.aggregate(Arrays.asList(borderingCountriesCollection,
      match(Filters.eq("borderingCountries", maxValue)))).first();
       
    assertTrue(maxNeighboredCountry.containsValue("China"));
}

Danach werden wir, wie wir zuvor gesehen haben, gruppieren die projizierte Sammlung, um das Maximum zu finden Wert von borderingCountries . Eine Sache, auf die hier hingewiesen werden sollte, ist, dass das max Akkumulator gibt uns den Maximalwert als Zahl , nicht das gesamte Dokument den Maximalwert enthält. Wir müssen Match durchführen um das gewünschte Dokument herauszufiltern wenn weitere Operationen durchgeführt werden sollen.