Agrégations MongoDB utilisant Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons plonger dans le framework MongoDB Aggregation à l'aide du pilote MongoDB Java .

Nous allons d'abord examiner ce que signifie l'agrégation sur le plan conceptuel, puis configurer un ensemble de données. Enfin, nous verrons diverses techniques d'agrégation en action à l'aide du générateur d'agrégats .

2. Que sont les agrégations?

Les agrégations sont utilisées dans MongoDB pour analyser les données et en tirer des informations significatives .

Celles-ci sont généralement effectuées en différentes étapes, et les étapes forment un pipeline - de sorte que la sortie d'un étage est transmise comme entrée à l'étape suivante.

Les étapes les plus couramment utilisées peuvent être résumées comme suit:

Étape Équivalent SQL La description
projet SÉLECTIONNER sélectionne uniquement les champs obligatoires, peut également être utilisé pour calculer et ajouter des champs dérivés à la collection
rencontre filtre la collection selon les critères spécifiés
groupe PAR GROUPE rassemble les entrées selon les critères spécifiés (par exemple, nombre, somme) pour renvoyer un document pour chaque regroupement distinct
Trier COMMANDÉ PAR trie les résultats par ordre croissant ou décroissant d'un champ donné
compter COMPTER compte les documents que contient la collection
limite LIMITE limite le résultat à un nombre spécifié de documents, au lieu de renvoyer la collection entière
en dehors SELECT INTO NEW_TABLE écrit le résultat dans une collection nommée; cette étape n'est acceptable que comme la dernière d'un pipeline

L'équivalent SQL pour chaque étape d'agrégation est inclus ci-dessus pour nous donner une idée de ce que ladite opération signifie dans le monde SQL.

Nous examinerons sous peu des exemples de code Java pour toutes ces étapes. Mais avant cela, nous avons besoin d'une base de données.

3. Configuration de la base de données

3.1. Base de données

La première et la plus importante condition pour apprendre tout ce qui concerne la base de données est l'ensemble de données lui-même!

Pour les besoins de ce didacticiel, nous utiliserons un point de terminaison d'API de repos accessible au public qui fournit des informations complètes sur tous les pays du monde. Cette API nous donne beaucoup de points de données pour un pays dans un format JSON pratique . Certains des champs que nous utiliserons dans notre analyse sont:

  • nom - le nom du pays; par exemple, États-Unis d'Amérique
  • alpha3Code - un shortcode pour le nom du pays; par exemple, IND (pour l'Inde)

  • région - la région à laquelle appartient le pays; par exemple, l' Europe
  • area - la zone géographique du pays
  • langues - langues officielles du pays dans un format de tableau; par exemple, anglais
  • frontières - un tableau des alpha3Code s des pays voisins

Voyons maintenant comment convertir ces données en une collection dans une base de données MongoDB .

3.2. Importation vers MongoDB

Tout d'abord, nous devons atteindre le point de terminaison de l'API pour obtenir tous les pays et enregistrer la réponse localement dans un fichier JSON . L'étape suivante consiste à l'importer dans MongoDB à l'aide de la commande mongoimport :

mongoimport.exe --db  --collection  --file  --jsonArray

Une importation réussie devrait nous donner une collection de 250 documents.

4. Exemples d'agrégation en Java

Maintenant que les bases sont couvertes, commençons à tirer des informations significatives à partir des données dont nous disposons pour tous les pays . Nous utiliserons plusieurs tests JUnit à cet effet.

Mais avant de faire cela, nous devons établir une connexion à la base de données:

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

Dans tous les exemples qui suivent, nous utiliserons la classe d'assistance Aggregates fournie par le pilote Java MongoDB.

Pour une meilleure lisibilité de nos extraits, nous pouvons ajouter une importation statique:

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

4.1. correspondre et compter

Pour commencer, commençons par quelque chose de simple. Nous avons noté précédemment que l'ensemble de données contient des informations sur les langues.

Maintenant, disons que nous voulons vérifier le nombre de pays dans le monde où l'anglais est une langue officielle :

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

Ici, nous utilisons deux étapes dans notre pipeline d'agrégation: correspondance et comptage .

Tout d'abord, nous filtrons la collection pour qu'elle corresponde uniquement aux documents contenant de l' anglais dans leur champ de langue . Ces documents peuvent être imaginés comme une collection temporaire ou intermédiaire qui devient l'entrée de notre prochaine étape, compter. Cela compte le nombre de documents à l'étape précédente.

Un autre point à noter dans cet exemple est l'utilisation de la méthode en premier . Puisque nous savons que la sortie de la dernière étape, count , sera un seul enregistrement, c'est un moyen garanti d'extraire le seul document résultant.

4.2. group (with sum) and sort

In this example, our objective is to find out the geographical region containing the maximum number of countries:

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

As is evident, we are using group and sort to achieve our objective here.

First, we gather the number of countries in each region by accumulating a sum of their occurrences in a variable tally. This gives us an intermediate collection of documents, each containing two fields: the region and the tally of countries in it. Then we sort it in the descending order and extract the first document to give us the region with maximum countries.

4.3. sort,limit, and out

Now let's use sort, limit and out to extract the seven largest countries area-wise and write them into a new collection:

@Test public void givenCountryCollection_whenAreaSortedDescending_thenSuccess() { collection.aggregate(Arrays.asList( sort(Sorts.descending("area")), limit(7), out("largest_seven"))).toCollection(); MongoCollection largestSeven = database.getCollection("largest_seven"); assertEquals(7, largestSeven.countDocuments()); Document usa = largestSeven.find(Filters.eq("alpha3Code", "USA")).first(); assertNotNull(usa); }

Here, we first sorted the given collection in the descending order of area. Then, we used the Aggregates#limit method to restrict the result to seven documents only. Finally, we used the out stage to deserialize this data into a new collection called largest_seven. This collection can now be used in the same way as any other – for example, to find if it contains USA.

4.4. project, group (with max), match

In our last sample, let's try something trickier. Say we need to find out how many borders each country shares with others, and what is the maximum such number.

Now in our dataset, we have a borders field, which is an array listing alpha3Codes for all bordering countries of the nation, but there isn't any field directly giving us the count. So we'll need to derive the number of borderingCountries using project:

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

After that, as we saw before, we'll group the projected collection to find the max value of borderingCountries. One thing to point out here is that the max accumulator gives us the maximum value as a number, not the entire Document containing the maximum value. We need to perform match to filter out the desired Document if any further operations are to be performed.

5. Conclusion

In this article, we saw what are MongoDB aggregations, and how to apply them in Java using an example dataset.

Nous avons utilisé quatre échantillons pour illustrer les différentes étapes d'agrégation afin de former une compréhension de base du concept. Ce cadre offre d'innombrables possibilités d'analyse de données qui peuvent être explorées plus avant .

Pour en savoir plus, Spring Data MongoDB fournit un moyen alternatif de gérer les projections et les agrégations en Java.

Comme toujours, le code source est disponible sur sur GitHub.