1. Oversigt
I denne øvelse tager vi et dyk ned i MongoDB Aggregation-rammeværket ved hjælp af MongoDB Java-driveren .
Vi vil først se på, hvad aggregering betyder konceptuelt, og derefter opsætte et datasæt. Til sidst vil vi se forskellige aggregeringsteknikker i aktion ved hjælp af Aggregates Builder .
2. Hvad er sammenlægninger?
Aggregationer bruges i MongoDB til at analysere data og udlede meningsfuld information ud af dem .
Disse udføres normalt i forskellige trin, og trinene danner en pipeline – sådan at outputtet fra et trin videregives som input til det næste trin.
De mest almindeligt anvendte stadier kan opsummeres som:
Stage | SQL-ækvivalent | Beskrivelse |
---|---|---|
projekt | VÆLG | vælger kun de påkrævede felter, kan også bruges til at beregne og tilføje afledte felter til samlingen |
match | HVOR | filtrerer samlingen i henhold til angivne kriterier |
gruppe | GRUPPER EFTER | samler input i henhold til de angivne kriterier (f.eks. antal, sum) for at returnere et dokument for hver særskilte gruppering |
sortér | BEstil efter | sorterer resultaterne i stigende eller faldende rækkefølge for et givet felt |
tæller | COUNT | tæller de dokumenter, samlingen indeholder |
grænse | LIMIT | begrænser resultatet til et bestemt antal dokumenter i stedet for at returnere hele samlingen |
ud | VÆLG I NEW_TABEL | skriver resultatet til en navngivet samling; denne fase er kun acceptabel som den sidste i en pipeline |
SQL-ækvivalenten for hvert aggregeringstrin er inkluderet ovenfor for at give os en idé om, hvad den nævnte operation betyder i SQL-verdenen.
Vi vil snart se på Java-kodeeksempler for alle disse stadier. Men før det har vi brug for en database.
3. Databaseopsætning
3.1. Datasæt
Det første og fremmeste krav for at lære noget databaserelateret er selve datasættet!
Til formålet med denne øvelse bruger vi et offentligt tilgængeligt afslappende API-slutpunkt, der giver omfattende information om alle verdens lande. Denne API giver os en masse datapunkter for et land i et praktisk JSON-format . Nogle af de felter, vi vil bruge i vores analyse, er:
- navn – landets navn; for eksempel Amerikas Forenede Stater
- alpha3Code – en kortkode for landenavnet; for eksempel IND (for Indien)
- region – den region, landet tilhører; f.eks. Europa
- område – landets geografiske område
- sprog – landets officielle sprog i et array-format; for eksempel engelsk
- grænser – en række nabolandes alpha3Code s
Lad os nu se hvordan man konverterer disse data til en samling i en MongoDB-database .
3.2. Importerer til MongoDB
Først skal vi ramme API-slutpunktet for at hente alle lande og gemme svaret lokalt i en JSON-fil . Det næste trin er at importere det til MongoDB ved hjælp af mongoimport kommando:
mongoimport.exe --db <db_name> --collection <collection_name> --file <path_to_file> --jsonArray
Vellykket import skulle give os en samling med 250 dokumenter.
4. Aggregationseksempler i Java
Nu hvor vi har dækket baserne, lad os komme ind på at udlede nogle meningsfulde indsigter fra de data, vi har for alle landene . Vi vil bruge flere JUnit-tests til dette formål.
Men før vi gør det, skal vi oprette forbindelse til databasen:
@BeforeClass
public static void setUpDB() throws IOException {
mongoClient = MongoClients.create();
database = mongoClient.getDatabase(DATABASE);
collection = database.getCollection(COLLECTION);
}
I alle de følgende eksempler bruger vi aggregaterne hjælperklasse leveret af MongoDB Java-driveren.
For bedre læsbarhed af vores uddrag kan vi tilføje en statisk import:
import static com.mongodb.client.model.Aggregates.*;
4.1. match og tæller
Til at begynde med, lad os starte med noget simpelt. Tidligere bemærkede vi, at datasættet indeholder information om sprog.
Lad os nu sige, at vi vil tjekke antallet af lande i verden, hvor engelsk er et officielt sprog :
@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"));
}
Her bruger vi to faser i vores aggregeringspipeline:match og tæller .
Først filtrerer vi samlingen fra, så den kun matcher de dokumenter, der indeholder engelsk på deres sprog Mark. Disse dokumenter kan forestilles som en midlertidig eller mellemliggende samling, der bliver input til vores næste fase, count. Dette tæller antallet af dokumenter i det foregående trin.
Et andet punkt at bemærke i dette eksempel er brugen af metoden først . Da vi ved, at outputtet fra det sidste trin, tæller , bliver en enkelt post, er dette en garanteret måde at udtrække det enlige resulterende dokument.
4.2. gruppe (med sum ) og sortér
I dette eksempel er vores mål at finde ud af den geografiske region, der indeholder det maksimale antal lande :
@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"));
}
Som det er tydeligt, bruger vi gruppe og sortér for at nå vores mål her .
Først samler vi antallet af lande i hver region ved at akkumulere en sum af deres forekomster i en variabel tally. Dette giver os en mellemliggende samling af dokumenter, der hver indeholder to felter:regionen og opgørelsen af landene i den. Derefter sorterer vi det i faldende rækkefølge og udtrækker det første dokument for at give os regionen med det maksimale antal lande.
4.3. sortér, grænse, og ud
Lad os nu bruge sort , grænse og ud at udtrække de syv største lande områdemæssigt og skrive dem ind 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);
}
Her sorterede vi først den givne samling i faldende rækkefølge efter område. Derefter brugte vi Aggregates#limit metode til at begrænse resultatet til kun syv dokumenter. Til sidst brugte vi out fase for at deserialisere disse data til en ny samling kaldet largest_seven . Denne samling kan nu bruges på samme måde som enhver anden – for eksempel til at finde hvis den indeholder USA.
4.4. projekt, gruppe (med max), match
I vores sidste eksempel, lad os prøve noget mere vanskeligt. Lad os sige, at vi skal finde ud af, hvor mange grænser hvert land deler med andre, og hvad det maksimale antal er .
Nu i vores datasæt har vi en grænser felt, som er et array med alpha3Code s for alle grænsende lande i nationen, men der er ikke noget felt, der direkte giver os optællingen. Så vi bliver nødt til at udlede antallet af grænselande ved hjælp af 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"));
}
Derefter, som vi så før, grupperer vi den forventede samling for at finde max værdien af grænselande . En ting at påpege her er, at det maks. akkumulator giver os den maksimale værdi som et tal , ikke hele dokumentet indeholdende den maksimale værdi. Vi skal udføre match for at filtrere det ønskede Dokument fra hvis der skal udføres yderligere operationer.