1. Visão geral
Neste tutorial, vamos mergulhar na estrutura de agregação do MongoDB usando o driver Java do MongoDB .
Veremos primeiro o que a agregação significa conceitualmente e, em seguida, configuraremos um conjunto de dados. Por fim, veremos várias técnicas de agregação em ação usando o construtor Aggregates .
2. O que são agregações?
As agregações são usadas no MongoDB para analisar dados e obter informações significativas a partir deles .
Geralmente, eles são executados em vários estágios, e os estágios formam um pipeline – de modo que a saída de um estágio é passada como entrada para o próximo estágio.
As etapas mais comumente usadas podem ser resumidas como:
Palco | Equivalente SQL | Descrição |
---|---|---|
projeto | SELECT | seleciona apenas os campos obrigatórios, também pode ser usado para calcular e adicionar campos derivados à coleção |
correspondência | ONDE | filtra a coleção de acordo com os critérios especificados |
grupo | GROUP BY | reúne entradas de acordo com os critérios especificados (por exemplo, contagem, soma) para retornar um documento para cada agrupamento distinto |
classificar | ORDER POR | classifica os resultados em ordem crescente ou decrescente de um determinado campo |
contagem | COUNT | conta os documentos que a coleção contém |
limite | LIMIT | limita o resultado a um número especificado de documentos, em vez de retornar a coleção inteira |
fora | SELECT INTO NEW_TABLE | grava o resultado em uma coleção nomeada; este estágio só é aceitável como o último em um pipeline |
O equivalente de SQL para cada estágio de agregação está incluído acima para nos dar uma ideia do que a referida operação significa no mundo SQL.
Veremos em breve exemplos de código Java para todos esses estágios. Mas antes disso, precisamos de um banco de dados.
3. Configuração do banco de dados
3.1. Conjunto de dados
O primeiro e mais importante requisito para aprender qualquer coisa relacionada a banco de dados é o próprio conjunto de dados!
Para os propósitos deste tutorial, usaremos um endpoint de API repousante disponível publicamente que fornece informações abrangentes sobre todos os países do mundo. Esta API nos fornece muitos pontos de dados para um país em um formato JSON conveniente . Alguns dos campos que usaremos em nossa análise são:
- nome – o nome do país; por exemplo, Estados Unidos da América
- alpha3Code – um shortcode para o nome do país; por exemplo, IND (para a Índia)
- região – a região a que o país pertence; por exemplo, Europa
- área – a área geográfica do país
- idiomas – línguas oficiais do país em formato array; por exemplo, inglês
- fronteiras – uma série de alpha3Code de países vizinhos s
Agora vamos ver como converter esses dados em uma coleção em um banco de dados MongoDB .
3.2. Importando para o MongoDB
Primeiro, precisamos atingir o endpoint da API para obter todos os países e salvar a resposta localmente em um arquivo JSON . O próximo passo é importá-lo para o MongoDB usando o mongoimport comando:
mongoimport.exe --db <db_name> --collection <collection_name> --file <path_to_file> --jsonArray
A importação bem-sucedida deve nos dar uma coleção com 250 documentos.
4. Amostras de agregação em Java
Agora que temos as bases cobertas, vamos começar a tirar alguns insights significativos dos dados que temos para todos os países . Usaremos vários testes JUnit para esta finalidade.
Mas antes de fazermos isso, precisamos fazer uma conexão com o banco de dados:
@BeforeClass
public static void setUpDB() throws IOException {
mongoClient = MongoClients.create();
database = mongoClient.getDatabase(DATABASE);
collection = database.getCollection(COLLECTION);
}
Em todos os exemplos a seguir, usaremos os Agregados classe auxiliar fornecida pelo driver Java do MongoDB.
Para melhor legibilidade de nossos snippets, podemos adicionar uma importação estática:
import static com.mongodb.client.model.Aggregates.*;
4.1. corresponder e contagem
Para começar, vamos começar com algo simples. Anteriormente, observamos que o conjunto de dados contém informações sobre idiomas.
Agora, digamos que queremos verificar o número de países no mundo onde o inglês é a língua oficial :
@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"));
}
Aqui estamos usando dois estágios em nosso pipeline de agregação:match e contagem .
Primeiro, filtramos a coleção para corresponder apenas aos documentos que contêm inglês em seus idiomas campo. Esses documentos podem ser imaginados como uma coleção temporária ou intermediária que se torna a entrada para nossa próxima etapa, contagem. Isso conta o número de documentos na etapa anterior.
Outro ponto a ser observado neste exemplo é o uso do método primeiro . Como sabemos que a saída do último estágio, count , será um único registro, esta é uma maneira garantida de extrair o único documento resultante.
4.2. grupo (com soma ) e classificar
Neste exemplo, nosso objetivo é descobrir a região geográfica que contém o número máximo de países :
@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"));
}
Como é evidente, estamos usando grupo e classificar para atingir nosso objetivo aqui .
Primeiro, reunimos o número de países em cada região acumulando uma soma de suas ocorrências em uma variável conta. Isso nos dá uma coleção intermediária de documentos, cada um contendo dois campos:a região e a contagem de países nela. Em seguida, classificamos em ordem decrescente e extraímos o primeiro documento para nos fornecer a região com o máximo de países.
4.3. classificar, limite, e fora
Agora vamos usar classificar , limite e fora para extrair os sete maiores países em termos de área e gravá-los em uma nova coleção :
@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);
}
Aqui, primeiro classificamos a coleção fornecida na ordem decrescente de área. Em seguida, usamos o Agregados#limit método para restringir o resultado a apenas sete documentos. Por fim, usamos o out etapa para desserializar esses dados em uma nova coleção chamada largest_seven . Esta coleção agora pode ser usada da mesma forma que qualquer outra – por exemplo, para encontrar se contiver EUA.
4.4. projeto, grupo (com máximo), correspondência
Em nosso último exemplo, vamos tentar algo mais complicado. Digamos que precisamos descobrir quantas fronteiras cada país compartilha com outros e qual é o número máximo desse número .
Agora, em nosso conjunto de dados, temos um bordas campo, que é um array listando alpha3Code s para todos os países limítrofes da nação, mas não há nenhum campo que nos dê a contagem diretamente. Portanto, precisaremos derivar o número de borderingCountries usando projeto :
@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"));
}
Depois disso, como vimos antes, vamos agrupar a coleção projetada para encontrar o máximo valor de borderingCountries . Uma coisa a salientar aqui é que o máximo acumulador nos dá o valor máximo como um número , não todo o Documento contendo o valor máximo. Precisamos realizar correspondência para filtrar o Documento desejado se quaisquer outras operações devem ser executadas.