MongoDB Aggregation

Fazer buscas mais complexas e unir vários documentos, com o Aggregation Framework.

[ Hits: 3.403 ]

Por: Alisson Machado em 24/10/2017


Introdução



Em minha jornada infinita de aprender coisas novas em T.I., nos assuntos DevOps, BigData, DataScience, Clusters, Virtualização e tudo mais.

Estou essa semana focado em extrair relatórios do MongoDB para fazer learning analytics pro Moodle, como o MongoDB é um banco de dados noSQL, não existe o relacionamento entre tabelas, como somos acostumados em bancos de dados SQL.

Sendo assim, para fazer buscas mais complexas e unir vários documentos, pode-se usar o Aggregation Framework.

Aggregation é uma forma de processar documentos distintos com o objetivo de agrupar em uma única saída, facilitando assim a geração de resultados e performance na hora de efetuar essas buscas.

Abaixo, vou explicar vários parâmetros sobre como utilizar esse recurso e elaborar buscas mais específicas.

ATENÇÃO: todos os comandos abaixo foram executados na versão 3.4 do MongoDB.

mongo
MongoDB shell version: 3.2.11
connecting to: test
use exemplo
switched to db exemplo


No log acima, entrei no console do MongoDB e acessei o banco exemplo, nesse banco vou criar uma collection chamada "funcionários" e inserir alguns registros:

db.funcionarios.insert({"nome":"Alisson","sobrenome":"Machado de Menezes","cargo":"Analista de Sistemas DevOps", "empresa":"4Linux"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Mariana","sobrenome":"Albano","cargo":"Analista de Sistemas DevOps", "empresa":"4Linux"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Antonio","sobrenome":"Gomes","cargo":"Supervidor de Suporte", "empresa":"4Linux"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Gabriel","sobrenome":"Bonfim","cargo":"Desenvolvedor Senior", "empresa":"4Linux"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Hederson","sobrenome":"Boechat","cargo":"Desenvolvedor Senior", "empresa":"Nadir"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Guilherme","sobrenome":"Chagas","cargo":"Analista de Sistemas DevOps", "empresa":"BankFacil"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Hederson","sobrenome":"Boechat","cargo":"Desenvolvedor Senior", "empresa":"Nadir"})
WriteResult({ "nInserted" : 1 })

db.funcionarios.insert({"nome":"Fernando","sobrenome":"Paiva","cargo":"Analista de B.I", "empresa":"Lemman"})
WriteResult({ "nInserted" : 1 })

Para listar todos os documentos, digite a instrução abaixo:

db.funcionarios.find()
{ "_id" : ObjectId("58a7479844f122d1903c551f"), "nome" : "Alisson", "sobrenome" : "Machado de Menezes", "cargo" : "Analista de Sistemas DevOps", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747a144f122d1903c5520"), "nome" : "Mariana", "sobrenome" : "Albano", "cargo" : "Analista de Sistemas DevOps", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747ac44f122d1903c5521"), "nome" : "Antonio", "sobrenome" : "Gomes", "cargo" : "Supervidor de Suporte", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747b644f122d1903c5522"), "nome" : "Gabriel", "sobrenome" : "Bonfim", "cargo" : "Desenvolvedor Senior", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747c044f122d1903c5523"), "nome" : "Hederson", "sobrenome" : "Boechat", "cargo" : "Desenvolvedor Senior", "empresa" : "Nadir" }
{ "_id" : ObjectId("58a747c844f122d1903c5524"), "nome" : "Guilherme", "sobrenome" : "Chagas", "cargo" : "Analista de Sistemas DevOps", "empresa" : "BankFacil" }
{ "_id" : ObjectId("58a747d144f122d1903c5525"), "nome" : "Hederson", "sobrenome" : "Boechat", "cargo" : "Desenvolvedor Senior", "empresa" : "Nadir" }
{ "_id" : ObjectId("58a747da44f122d1903c5526"), "nome" : "Fernando", "sobrenome" : "Paiva", "cargo" : "Analista de B.I", "empresa" : "Lemman" }


Agora que a base dados já está populada, é possível utilizar do Aggregate para filtrar essas buscas. Por exemplo, se eu quiser buscar todos os funcionários que trabalham na empresa 4linux:

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}}])
{ "_id" : ObjectId("58a7479844f122d1903c551f"), "nome" : "Alisson", "sobrenome" : "Machado de Menezes", "cargo" : "Analista de Sistemas DevOps", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747a144f122d1903c5520"), "nome" : "Mariana", "sobrenome" : "Albano", "cargo" : "Analista de Sistemas DevOps", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747ac44f122d1903c5521"), "nome" : "Antonio", "sobrenome" : "Gomes", "cargo" : "Supervidor de Suporte", "empresa" : "4Linux" }
{ "_id" : ObjectId("58a747b644f122d1903c5522"), "nome" : "Gabriel", "sobrenome" : "Bonfim", "cargo" : "Desenvolvedor Senior", "empresa" : "4Linux" }


Caso queira agrupar os valores, é possível utilizando a instrução $group. Essa instrução, obrigatoriamente, precisa que seja passado um _id e esse aí deve ser um campo do documento retornado.

Por exemplo:

$ db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$group":{"_id":"$nome"}}])
{ "_id" : "Gabriel" }
{ "_id" : "Mariana" }
{ "_id" : "Antonio" }
{ "_id" : "Alisson" }


Para ver o total de documentos agrupados, pode-se utilizar a instrução $sum:

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$group":{"_id":"$empresa","total":{"$sum":1}}}])
{ "_id" : "4Linux", "total" : 4 }

Para contar todos os resultados sem o agrupamento, pode-se utilizar a instrução $count, essa instrução só existe a partir da versão 3.4:

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$count":"total"}])

É possível também projetar uma saída, ou seja, modelar o documento e mostrar apenas campos específicos aumentando a performance da sua busca e trazendo resultados mais fáceis de se encontrar. Por exemplo:

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$project":{"nome":1,"cargo":1}}])
{ "_id" : ObjectId("58a7479844f122d1903c551f"), "nome" : "Alisson", "cargo" : "Analista de Sistemas DevOps" }
{ "_id" : ObjectId("58a747a144f122d1903c5520"), "nome" : "Mariana", "cargo" : "Analista de Sistemas DevOps" }
{ "_id" : ObjectId("58a747ac44f122d1903c5521"), "nome" : "Antonio", "cargo" : "Supervidor de Suporte" }
{ "_id" : ObjectId("58a747b644f122d1903c5522"), "nome" : "Gabriel", "cargo" : "Desenvolvedor Senior" }


No exemplo acima, pode-se ver que foi foram mostrados somente os campos _id, nome e cargo, sendo assim, quando se quer mostrar um campo, coloca-se o valor 1 em conjunto com a chave; caso não queira, pode-se colocar o valor 0.

Por exemplo:

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$project":{"nome":1,"cargo":1,"_id":0}}])
{ "nome" : "Alisson", "cargo" : "Analista de Sistemas DevOps" }
{ "nome" : "Mariana", "cargo" : "Analista de Sistemas DevOps" }
{ "nome" : "Antonio", "cargo" : "Supervidor de Suporte" }
{ "nome" : "Gabriel", "cargo" : "Desenvolvedor Senior" }


No exemplo acima foi ocultado o campo _id, para melhorar a visualização do documento.

O Aggregation do MongoDB trabalha com um esquema de pipeline, ou seja, você pode concatenar todas as instruções juntas.

Por exemplo: pode-se fazer um $match, depois um $project para limitar os campos e depois um $group, para agrupar pelos cargo e saber quantas pessoas daquela posição existem na empresa.

db.funcionarios.aggregate([{"$match":{"empresa":"4Linux"}},{"$project":{"nome":1,"cargo":1,"_id":0}},{"$group":{"_id":"$cargo","total":{"$sum":1}}}])
{ "_id" : "Desenvolvedor Senior", "total" : 1 }
{ "_id" : "Supervidor de Suporte", "total" : 1 }
{ "_id" : "Analista de Sistemas DevOps", "total" : 2 }


Esses são os comandos básicos para fazer um Aggregate no MongoDB.

Qualquer dúvida, é só me dar um salve.
Alisson Machado - http://alissonmachado.com.br

   

Páginas do artigo
   1. Introdução
Outros artigos deste autor

Python Flask Básico

Python + ADB

Sockets em Python

paramiko - Python + SSH

Vault: SSH com OneTimePassword

Leitura recomendada

Injeção de SQL

Entendendo o LDAP

Gerencie suas informações através de instruções SQL com selects turbinados (para leigos e experts)

Implementação LDAP e Java

Instalando o poderoso banco de dados IBM DB2!

  
Comentários
[1] Comentário enviado por iksme em 13/11/2017 - 17:43h

Parabéns pelo artigo, não vou poder testar porquê decidir usar mongo hoje em um projeto mas tenho certeza que vou essa técnica de aggregation.


Contribuir com comentário