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