MongoDB агрегации, използващи Java

1. Общ преглед

В този урок ще се потопим в MongoDB Aggregation framework, използвайки MongoDB Java драйвер .

Първо ще разгледаме какво означава концептуално обобщаването и след това ще настроим набор от данни. И накрая, ще видим различни техники за агрегиране в действие, използвайки Aggregates builder .

2. Какво представляват агрегациите?

Агрегациите се използват в MongoDB за анализ на данни и извличане на значима информация от тях .

Те обикновено се изпълняват на различни етапи и етапите образуват тръбопровод - такъв, че изходът от един етап се предава като вход към следващия етап.

Най-често използваните етапи могат да бъдат обобщени като:

сцена SQL еквивалент Описание
проект ИЗБЕРЕТЕ избира само задължителните полета, може да се използва и за изчисляване и добавяне на производни полета към колекцията
съвпада КЪДЕТО филтрира колекцията според определени критерии
група ГРУПИРАЙ ПО събира входящи данни според посочените критерии (напр. брой, сума), за да върне документ за всяко отделно групиране
вид ПОДРЕДЕНИ ПО сортира резултатите във възходящ или низходящ ред на дадено поле
броя БРОЯ брои документите, които колекцията съдържа
граница ГРАНИЦА ограничава резултата до определен брой документи, вместо да връща цялата колекция
навън ИЗБЕРЕТЕ В НОВА ТАБЛИЦА записва резултата в посочена колекция; този етап е приемлив само като последен в тръбопровод

SQL еквивалентът за всеки етап на агрегиране е включен по-горе, за да ни даде представа какво означава споменатата операция в SQL света.

Ще разгледаме примери на Java кодове за всички тези етапи скоро. Но преди това се нуждаем от база данни.

3. Настройка на база данни

3.1. Набор от данни

Първото и основно изискване за научаване на каквото и да е свързано с база данни е самият набор от данни!

За целите на този урок ще използваме публично достъпна успокояваща крайна точка на API, която предоставя изчерпателна информация за всички страни по света. Този API ни дава много точки от данни за държава в удобен JSON формат . Някои от полетата, които ще използваме в нашия анализ, са:

  • име - името на държавата; например Съединените американски щати
  • alpha3Code - кратък код за името на държавата; например IND (за Индия)

  • регион - регионът, към който принадлежи държавата; например Европа
  • площ - географският район на страната
  • езици - официални езици на страната във формат масив; например английски
  • граници - масив от съседните страни alpha3Code ите

Сега нека видим как да конвертираме тези данни в колекция в база данни MongoDB .

3.2. Импортиране в MongoDB

Първо, трябва да ударим крайната точка на API, за да получим всички държави и да запишем отговора локално в JSON файл . Следващата стъпка е да го импортирате в MongoDB с помощта на командата mongoimport :

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

Успешното импортиране трябва да ни даде колекция с 250 документа.

4. Примери за агрегиране в Java

Сега, когато имаме основите, нека разгледаме смислени прозрения от данните, които имаме за всички страни . За тази цел ще използваме няколко теста JUnit.

Но преди да направим това, трябва да установим връзка с базата данни:

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

Във всички примери, които следват, ще използваме помощния клас Aggregates, предоставен от драйвера на MongoDB Java.

За по-добра четливост на нашите фрагменти можем да добавим статичен импорт:

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

4.1. съвпадение и преброяване

Като начало, нека започнем с нещо просто. По-рано отбелязахме, че наборът от данни съдържа информация за езиците.

Да кажем, че искаме да проверим броя на страните в света, където английският е официален език :

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

Here we are using two stages in our aggregation pipeline: match and count.

First, we filter out the collection to match only those documents that contain English in their languages field. These documents can be imagined as a temporary or intermediate collection that becomes the input for our next stage, count. This counts the number of documents in the previous stage.

Another point to note in this sample is the use of the method first. Since we know that the output of the last stage, count, is going to be a single record, this is a guaranteed way to extract out the lone resulting document.

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.

Използвахме четири проби, за да илюстрираме различните етапи на агрегиране, за да формираме основно разбиране на концепцията. Има много възможности за анализ на данни, които тази рамка предлага, които могат да бъдат изследвани допълнително .

За по-нататъшно четене Spring Data MongoDB предоставя алтернативен начин за обработка на прогнози и агрегации в Java.

Както винаги, изходният код е достъпен в GitHub.