sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB Aggregations med Java

1. Översikt

I den här handledningen tar vi ett dyk in i MongoDB Aggregation-ramverket med MongoDB Java-drivrutinen .

Vi ska först titta på vad aggregering betyder begreppsmässigt och sedan ställa in en datauppsättning. Slutligen kommer vi att se olika aggregeringstekniker i aktion med hjälp av Aggregates builder .

2. Vad är aggregationer?

Aggregationer används i MongoDB för att analysera data och härleda meningsfull information ur den .

Dessa utförs vanligtvis i olika steg och stegen bildar en pipeline – så att utdata från ett steg förs vidare som input till nästa steg.

De vanligaste stegen kan sammanfattas som:

Scen SQL-ekvivalent Beskrivning
 projekt VÄLJ väljer endast de obligatoriska fälten, kan även användas för att beräkna och lägga till härledda fält till samlingen
 match VAR filtrerar samlingen enligt angivna kriterier
 grupp GRUPPA EFTER samlar indata enligt de angivna kriterierna (t.ex. antal, summa) för att returnera ett dokument för varje distinkt gruppering
 sortera BESTÄLL EFTER sorterar resultaten i stigande eller fallande ordning för ett givet fält
 count COUNT räcker dokumenten som samlingen innehåller
 gräns LIMIT begränsar resultatet till ett specificerat antal dokument, istället för att returnera hela samlingen
 out VÄLJ I NEW_TABELL skriver resultatet till en namngiven samling; detta steg är bara acceptabelt som det sista i en pipeline


SQL-ekvivalenten för varje aggregeringssteg ingår ovan för att ge oss en uppfattning om vad nämnda operation betyder i SQL-världen.

Vi kommer att titta på Java-kodexempel för alla dessa stadier inom kort. Men innan dess behöver vi en databas.

3. Databasinställningar

3.1. Datauppsättning

Det första och främsta kravet för att lära sig något databasrelaterat är själva datasetet!

För syftet med denna handledning kommer vi att använda en allmänt tillgänglig vilsam API-slutpunkt som ger omfattande information om alla världens länder. Detta API ger oss många datapunkter för ett land i ett bekvämt JSON-format . Några av fälten som vi kommer att använda i vår analys är:

  • namn – landets namn. till exempel Amerikas förenta stater
  • alpha3Code – en kortkod för landsnamnet; till exempel IND (för Indien)
  • region – den region landet tillhör; till exempel Europa
  • område – landets geografiska område
  • språk – landets officiella språk i ett arrayformat; till exempel engelska
  • gränser – en rad grannländers alpha3Code s

Låt oss nu se hur man konverterar denna data till en samling i en MongoDB-databas .

3.2. Importerar till MongoDB

Först måste vi träffa API-slutpunkten för att få alla länder och spara svaret lokalt i en JSON-fil . Nästa steg är att importera den till MongoDB med mongoimport kommando:

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

Lyckad import bör ge oss en samling med 250 dokument.

4. Aggregationsexempel i Java

Nu när vi har täckt grunderna, låt oss gå in på att ta fram några meningsfulla insikter från data vi har för alla länder . Vi kommer att använda flera JUnit-tester för detta ändamål.

Men innan vi gör det måste vi göra en anslutning till databasen:

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

I alla exempel som följer kommer vi att använda Aggregaten hjälparklass som tillhandahålls av MongoDB Java-drivrutinen.

För bättre läsbarhet för våra utdrag kan vi lägga till en statisk import:

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

4.1. match och räkna

Till att börja med, låt oss börja med något enkelt. Tidigare har vi noterat att datasetet innehåller information om språk.

Låt oss nu säga att vi vill kontrollera antalet länder i världen där engelska är ett officiellt språk :

@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"));
}

Här använder vi två steg i vår aggregeringspipeline:match och räkna .

Först filtrerar vi bort samlingen så att den bara matchar de dokument som innehåller engelska på deras språk fält. Dessa dokument kan föreställas som en tillfällig eller mellanliggande samling som blir input för vårt nästa steg, count. Detta räknar antalet dokument i föregående steg.

En annan punkt att notera i detta exempel är användningen av metoden först . Eftersom vi vet att resultatet från det sista steget, räkna , kommer att bli en enda post, detta är ett garanterat sätt att extrahera det ensamma resulterande dokumentet.

4.2. grupp (med summa ) och sortera

I det här exemplet är vårt mål att ta reda på den geografiska region som innehåller det maximala antalet länder :

@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"));
}

Det är uppenbart att vi använder grupp och sortera för att uppnå vårt mål här .

Först samlar vi antalet länder i varje region genom att samla en summa av deras förekomster i en variabel tally. Detta ger oss en mellanliggande samling av dokument, som vart och ett innehåller två fält:regionen och sammanställningen av länder i den. Sedan sorterar vi det i fallande ordning och extraherar det första dokumentet för att ge oss regionen med maximalt antal länder.

4.3. sortera, gräns, och ut

Låt oss nu använda sortera , gräns och ut att extrahera de sju största länderna områdesmässigt och skriva in dem i en ny samling :

@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);
}

Här sorterade vi först den givna samlingen i fallande ordning efter area. Sedan använde vi Aggregates#limit metod för att begränsa resultatet till endast sju dokument. Slutligen använde vi out steg för att deserialisera denna data till en ny samling som heter largest_seven . Den här samlingen kan nu användas på samma sätt som alla andra – till exempel för att hitta om den innehåller USA.

4.4. projekt, grupp (med max), match

I vårt sista exempel, låt oss prova något knepigare. Säg att vi måste ta reda på hur många gränser varje land delar med andra, och vad är det maximala antalet sådana .

Nu i vår datauppsättning har vi en gränser fält, som är en array som listar alpha3Code s för alla gränsländer i nationen, men det finns inte något fält som direkt ger oss räkningen. Så vi måste härleda antalet gränsländer med 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"));
}

Efter det, som vi såg tidigare, grupperar vi oss den beräknade samlingen för att hitta max värde för gränsande länder . En sak att påpeka här är att det max ackumulator ger oss det maximala värdet som ett tal , inte hela dokumentet som innehåller maxvärdet. Vi måste utföra match för att filtrera bort önskat dokument om ytterligare operationer ska utföras.


  1. Hur får man flera dokument med en array av MongoDb-id?

  2. Ta bort database.yml när du använder Mongoid i Rails 3.2

  3. Exponera Redis med Ingress Nginx Controller

  4. Kan inte ansluta till mongodb med maskinens ip