Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Saiba por que o MongoDB foi selecionado como um líder no 2024 Gartner_Magic Quadrupnt()
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
Javachevron-right

Pipeline de agregação Java

Maxime Beugnet8 min read • Published Feb 01, 2022 • Updated Oct 01, 2024
MongoDBFramework de agregaçãoJava
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty

Atualizações

O repositório de início rápido do MongoDB Java está disponível no GitHub.

28 de fevereiro de 2024

  • Atualizar para o Java 21
  • Atualize o driver Java para 5.0.0
  • Atualize logback-classic para 1.2.13

14 de novembro de 2023

  • Atualizar para o Java 17
  • Atualize o driver Java para 4.11.1
  • Atualize o mongodb-crypt para 1.8.0

25 de março de 2021

  • Atualize o driver Java para 4.2.2.
  • Exemplo de criptografia no nível do campo do lado do cliente adicionado.

21 de outubro de 2020

  • Atualize o driver Java para 4.1.1.
  • O registro do driver Java agora está ativado por meio da popular APIJ SLF4, portanto, adicionei logback no pom.xml e um arquivo de configuração logback.xml.

O que é o aggregation pipeline?

Emblema do Java
O aggregation pipeline é uma framework para agregação de dados modelada sobre o conceito de pipelines de processamento de dados, assim como o "pipe" no Linux Shell. Os documentos entram em um pipeline em vários estágios que transforma os documentos em resultados agregados.
É a maneira mais poderosa de trabalhar com seus dados no MongoDB. Ele nos permitirá fazer queries avançadas, como agrupar documentos, manipular arrays, remodelar modelos de documentos etc.
Vamos ver como podemos coletar esse poder usando Java.

Configuração

Usarei o mesmo repositório de sempre nesta série. Se você ainda não tiver uma cópia dele, poderá cloná-lo ou apenas atualizá-lo, caso já o tenha:
1git clone https://github.com/mongodb-developer/java-quick-start
Se você não configurou seu cluster gratuito no MongoDB Atlas, agora é um ótimo momento para fazê-lo. Você tem todas as instruções nesta postagem do blog.

Primeiro exemplo com zíperes

No Conjunto dedados de amostrado MongoDB no MongoDB Atlas, vamos explorar um pouco a coleção zipsno banco de dadossample_training.
1MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.zips.find({city:"NEW YORK"}).limit(2).pretty()
2{
3 "_id" : ObjectId("5c8eccc1caa187d17ca72f8a"),
4 "city" : "NEW YORK",
5 "zip" : "10001",
6 "loc" : {
7 "y" : 40.74838,
8 "x" : 73.996705
9 },
10 "pop" : 18913,
11 "state" : "NY"
12}
13{
14 "_id" : ObjectId("5c8eccc1caa187d17ca72f8b"),
15 "city" : "NEW YORK",
16 "zip" : "10003",
17 "loc" : {
18 "y" : 40.731253,
19 "x" : 73.989223
20 },
21 "pop" : 51224,
22 "state" : "NY"
23}
Como você pode ver, temos um documento para cada código postal nos EUA e, para cada um, temos a população associada.
Para calcular a população de Nova York, eu teria que somar a população de cada código postal para obter a população de toda a cidade.
Vamos tentar encontrar as 3 maiores cidades do estado do Texas. Vamos projetar isso no papel primeiro.
  • Não preciso trabalhar com a collection inteira. Preciso filtrar apenas as cidades do Texas.
  • Uma vez feito isso, posso reagrupar todos os códigos postais de uma mesma cidade para obter a população total.
  • Então, posso ordenar minhas cidades por ordem decrescente ou população.
  • Finalmente, posso manter as primeiras 3 cidades da minha lista.
A maneira mais fácil de construir este pipeline no MongoDB é usar o construtor de pipeline de agregação que está disponível no MongoDB Compass ou no MongoDB Atlas na guiaCollections .
Depois de fazer isso, você pode exportar seu pipeline para Java usando o botão Exportar.
Após uma pequena refatoração de código, aqui está o que eu tenho:
1/**
2 * find the 3 most densely populated cities in Texas.
3 * @param zips sample_training.zips collection from the MongoDB Sample Dataset in MongoDB Atlas.
4 */
5private static void threeMostPopulatedCitiesInTexas(MongoCollection<Document> zips) {
6 Bson match = match(eq("state", "TX"));
7 Bson group = group("$city", sum("totalPop", "$pop"));
8 Bson project = project(fields(excludeId(), include("totalPop"), computed("city", "$_id")));
9 Bson sort = sort(descending("totalPop"));
10 Bson limit = limit(3);
11
12 List<Document> results = zips.aggregate(List.of(match, group, project, sort, limit)).into(new ArrayList<>());
13 System.out.println("==> 3 most densely populated cities in Texas");
14 results.forEach(printDocuments());
15}
O driver do MongoDB oferece muitos ajudantes para tornar o código fácil de escrever e ler.
Como você pode ver, resolvi esse problema com:
  • Um estágio $match para filtrar meus documentos e manter apenas o código postal no Texas,
  • Um estágio $group para reagrupar meus códigos postais nas cidades,
  • Um estágio $project para renomear o campo _id em city para uma saída limpa (não obrigatório, mas sou elegante),
  • Um estágio $sort para classificar por população decrescente,
  • Um estágio $limit para manter apenas as 3 cidades mais populosas.
Esta é a saída que obtemos:
1==> 3 most densely populated cities in Texas
2{
3 "totalPop": 2095918,
4 "city": "HOUSTON"
5}
6{
7 "totalPop": 940191,
8 "city": "DALLAS"
9}
10{
11 "totalPop": 811792,
12 "city": "SAN ANTONIO"
13}
No MongoDB 4.2, há 30 diferentes agregação pipeline stages que você pode usar para manipular seus documentos. Se você quiser saber mais, recomendamos que siga este curso na MongoDB University: MongoDB Aggregation.

Segundo exemplo com publicações

Desta vez, estou usando a collection posts no mesmo banco de dados.
1MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.posts.findOne()
2{
3 "_id" : ObjectId("50ab0f8bbcf1bfe2536dc3f9"),
4 "body" : "Amendment I\n<p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.\n<p>\nAmendment II\n<p>\nA well regulated Militia, being necessary to the security of a free State, the right of the people to keep and bear Arms, shall not be infringed.\n<p>\nAmendment III\n<p>\nNo Soldier shall, in time of peace be quartered in any house, without the consent of the Owner, nor in time of war, but in a manner to be prescribed by law.\n<p>\nAmendment IV\n<p>\nThe right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no Warrants shall issue, but upon probable cause, supported by Oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.\n<p>\nAmendment V\n<p>\nNo person shall be held to answer for a capital, or otherwise infamous crime, unless on a presentment or indictment of a Grand Jury, except in cases arising in the land or naval forces, or in the Militia, when in actual service in time of War or public danger; nor shall any person be subject for the same offence to be twice put in jeopardy of life or limb; nor shall be compelled in any criminal case to be a witness against himself, nor be deprived of life, liberty, or property, without due process of law; nor shall private property be taken for public use, without just compensation.\n<p>\n\nAmendment VI\n<p>\nIn all criminal prosecutions, the accused shall enjoy the right to a speedy and public trial, by an impartial jury of the State and district wherein the crime shall have been committed, which district shall have been previously ascertained by law, and to be informed of the nature and cause of the accusation; to be confronted with the witnesses against him; to have compulsory process for obtaining witnesses in his favor, and to have the Assistance of Counsel for his defence.\n<p>\nAmendment VII\n<p>\nIn Suits at common law, where the value in controversy shall exceed twenty dollars, the right of trial by jury shall be preserved, and no fact tried by a jury, shall be otherwise re-examined in any Court of the United States, than according to the rules of the common law.\n<p>\nAmendment VIII\n<p>\nExcessive bail shall not be required, nor excessive fines imposed, nor cruel and unusual punishments inflicted.\n<p>\nAmendment IX\n<p>\nThe enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people.\n<p>\nAmendment X\n<p>\nThe powers not delegated to the United States by the Constitution, nor prohibited by it to the States, are reserved to the States respectively, or to the people.\"\n<p>\n",
5 "permalink" : "aRjNnLZkJkTyspAIoRGe",
6 "author" : "machine",
7 "title" : "Bill of Rights",
8 "tags" : [
9 "watchmaker",
10 "santa",
11 "xylophone",
12 "math",
13 "handsaw",
14 "dream",
15 "undershirt",
16 "dolphin",
17 "tanker",
18 "action"
19 ],
20 "comments" : [
21 {
22 "body" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum",
23 "email" : "HvizfYVx@pKvLaagH.com",
24 "author" : "Santiago Dollins"
25 },
26 {
27 "body" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum",
28 "email" : "glbeRCMi@KwnNwhzl.com",
29 "author" : "Omar Bowdoin"
30 }
31 ],
32 "date" : ISODate("2012-11-20T05:05:15.231Z")
33}
Esta coleção de postagens 500 foi gerada artificialmente, mas contém matrizes e quero mostrar como podemos manipular matrizes em um pipeline.
Vamos tentar encontrar as três tags mais populares e, para cada tag, também quero a lista de títulos de postagens que eles estão marcando.
Aqui está a minha solução em Java.
1/**
2 * find the 3 most popular tags and their post titles
3 * @param posts sample_training.posts collection from the MongoDB Sample Dataset in MongoDB Atlas.
4 */
5private static void threeMostPopularTags(MongoCollection<Document> posts) {
6 Bson unwind = unwind("$tags");
7 Bson group = group("$tags", sum("count", 1L), push("titles", "$title"));
8 Bson sort = sort(descending("count"));
9 Bson limit = limit(3);
10 Bson project = project(fields(excludeId(), computed("tag", "$_id"), include("count", "titles")));
11
12 List<Document> results = posts.aggregate(List.of(unwind, group, sort, limit, project)).into(new ArrayList<>());
13 System.out.println("==> 3 most popular tags and their posts titles");
14 results.forEach(printDocuments());
15}
Aqui estou usando o estágio $unwindmuito útil para quebrar minha array de tags.
Ele me permite no estágio $group seguinte agrupar minhas marcações, contar as postagens e coletar os títulos em uma nova array titles.
Aqui está o resultado final que obtive.
1==> 3 most popular tags and their posts titles
2{
3 "count": 8,
4 "titles": [
5 "Gettysburg Address",
6 "US Constitution",
7 "Bill of Rights",
8 "Gettysburg Address",
9 "Gettysburg Address",
10 "Declaration of Independence",
11 "Bill of Rights",
12 "Declaration of Independence"
13 ],
14 "tag": "toad"
15}
16{
17 "count": 8,
18 "titles": [
19 "Bill of Rights",
20 "Gettysburg Address",
21 "Bill of Rights",
22 "Bill of Rights",
23 "Declaration of Independence",
24 "Declaration of Independence",
25 "Bill of Rights",
26 "US Constitution"
27 ],
28 "tag": "forest"
29}
30{
31 "count": 8,
32 "titles": [
33 "Bill of Rights",
34 "Declaration of Independence",
35 "Declaration of Independence",
36 "Gettysburg Address",
37 "US Constitution",
38 "Bill of Rights",
39 "US Constitution",
40 "US Constitution"
41 ],
42 "tag": "hair"
43}
Como você pode ver, alguns títulos são repetidos. Como eu disse anteriormente, a coleção foi gerada então os títulos das postagens não são únicos. Eu poderia resolver esse "problema" usando o operador $addToSet em vez do operador$push se isso fosse realmente um problema.

Código final

1package com.mongodb.quickstart;
2
3import com.mongodb.client.MongoClient;
4import com.mongodb.client.MongoClients;
5import com.mongodb.client.MongoCollection;
6import com.mongodb.client.MongoDatabase;
7import org.bson.Document;
8import org.bson.conversions.Bson;
9import org.bson.json.JsonWriterSettings;
10
11import java.util.ArrayList;
12import java.util.List;
13import java.util.function.Consumer;
14
15import static com.mongodb.client.model.Accumulators.push;
16import static com.mongodb.client.model.Accumulators.sum;
17import static com.mongodb.client.model.Aggregates.*;
18import static com.mongodb.client.model.Filters.eq;
19import static com.mongodb.client.model.Projections.*;
20import static com.mongodb.client.model.Sorts.descending;
21
22public class AggregationFramework {
23
24 public static void main(String[] args) {
25 String connectionString = System.getProperty("mongodb.uri");
26 try (MongoClient mongoClient = MongoClients.create(connectionString)) {
27 MongoDatabase db = mongoClient.getDatabase("sample_training");
28 MongoCollection<Document> zips = db.getCollection("zips");
29 MongoCollection<Document> posts = db.getCollection("posts");
30 threeMostPopulatedCitiesInTexas(zips);
31 threeMostPopularTags(posts);
32 }
33 }
34
35 /**
36 * find the 3 most densely populated cities in Texas.
37 *
38 * @param zips sample_training.zips collection from the MongoDB Sample Dataset in MongoDB Atlas.
39 */
40 private static void threeMostPopulatedCitiesInTexas(MongoCollection<Document> zips) {
41 Bson match = match(eq("state", "TX"));
42 Bson group = group("$city", sum("totalPop", "$pop"));
43 Bson project = project(fields(excludeId(), include("totalPop"), computed("city", "$_id")));
44 Bson sort = sort(descending("totalPop"));
45 Bson limit = limit(3);
46
47 List<Document> results = zips.aggregate(List.of(match, group, project, sort, limit)).into(new ArrayList<>());
48 System.out.println("==> 3 most densely populated cities in Texas");
49 results.forEach(printDocuments());
50 }
51
52 /**
53 * find the 3 most popular tags and their post titles
54 *
55 * @param posts sample_training.posts collection from the MongoDB Sample Dataset in MongoDB Atlas.
56 */
57 private static void threeMostPopularTags(MongoCollection<Document> posts) {
58 Bson unwind = unwind("$tags");
59 Bson group = group("$tags", sum("count", 1L), push("titles", "$title"));
60 Bson sort = sort(descending("count"));
61 Bson limit = limit(3);
62 Bson project = project(fields(excludeId(), computed("tag", "$_id"), include("count", "titles")));
63
64 List<Document> results = posts.aggregate(List.of(unwind, group, sort, limit, project)).into(new ArrayList<>());
65 System.out.println("==> 3 most popular tags and their posts titles");
66 results.forEach(printDocuments());
67 }
68
69 private static Consumer<Document> printDocuments() {
70 return doc -> System.out.println(doc.toJson(JsonWriterSettings.builder().indent(true).build()));
71 }
72}

Encerrando

O pipeline de agregação é muito poderoso. Acabamos de começar com esses dois exemplos, mas confie em mim se eu disser que é seu melhor aliado se você conseguir dominá-lo.
Convido você a seguir a agregação MongoDB para se tornar um jedi de pipeline de agregação .
Se você quiser aprender mais e afundar seu conhecimento com mais rapidez, recomendamos conferir o treinamento Caminho do desenvolvedor MongoDB Java disponível gratuitamente na MongoDB University.
Na próxima postagem do blog, explicarei a você os Change Streams em Java.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Uso do Azure Kubernetes Services para microsserviços Java com Spring Boot


Apr 15, 2024 | 9 min read
Tutorial

Spring Data Unlocked: Começando com Java e MongoDB


Nov 11, 2024 | 5 min read
Início rápido

Java - Change Streams


Oct 01, 2024 | 10 min read
Tutorial

Construindo um Painel de Vendas Dinâmico e em Tempo Real no MongoDB


Aug 05, 2024 | 7 min read
Sumário