Mongo Aggregation

O poder da transformação dos dados no lado das requisições

Rosa Bugan
Accenture Digital Product Dev
7 min readJul 13, 2020

--

Você já teve, em suas aplicações, que consultar o banco de dados, para depois poder fazer cálculos com estes dados? Pois é, frequentemente me deparo com este problema e recentemente me perguntei: e se eu já recebesse estes cálculos feitos quando fizer uma consulta ao banco de dados?

Para exemplificar minha dúvida, vamos supor que você queira fazer consultas que agrupem os dados para retornar um único resultado, e que isso possa ser executado diretamente nas queries do banco de dados. OK, você vai dizer que nos bancos SQL isso é fácil, “eu consigo fazer cálculos, como multiplicar um campo por outro, ou calcular a média ou a soma em uma consulta”.

Entretanto, em bancos não relacionais essas operações não são tão fáceis assim. No Mongo DB, por exemplo, elas são executadas por meio de funções de agregação, operações usadas para processar os dados que retornam os resultados calculados. A agregação basicamente agrupa os dados de vários documentos e opera de várias maneiras para retornar um resultado combinado. O MongoDB oferece três maneiras de executar a agregação: os métodos de agregação de finalidade única, a função de map reduce e o pipeline de agregação. Vamos falar de cada uma delas?

Métodos de agregação de finalidade única
A primeira maneira de executar a agregação no Mongo DB são os métodos de agregação de finalidade única, que são basicamente as funções db.collection.estimatedDocumentCount (), db.collection.count () e db.collection.distinct ().

Para exemplificar, vamos rodar os scripts na collection employees, na qual temos uma estrutura com a propriedade team, que pode ter um dos seguintes valores [“Blue”, “Green”, “Indigo”, “Orange”, “Red”, “Violet”, “Yellow”]. Utilizando os métodos acima, temos as seguintes respostas:

MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.employees.distinct(“team”)

[ “Blue”, “Green”, “Indigo”, “Orange”, “Red”, “Violet”, “Yellow” ]

MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.employees.count()

1000

MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.employees.countDocuments({})

1000

MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.employees.countDocuments({“team”:{$eq:”Violet”}})

151

MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.employees.estimatedDocumentCount()

1000

Todas essas operações agregam documentos de uma única coleção. Ou seja, embora essas operações ofereçam acessos simples a processos de agregação comuns, elas têm pouca flexibilidade.

Map-Reduce
Outra opção que o Mongo DB oferece para realizar agregação são as operações de map-reduce. Em geral, essas operações têm duas fases: um estágio de appeasement que processa cada documento e emite um ou mais objetos para cada documento de entrada, e a fase de redução, que combina a saída da operação de map. Como opção, o map-reduce pode ter um estágio de finalização para fazer as modificações finais no resultado.

Como outras operações de agregação, o map-reduce também pode especificar uma condição de consulta para selecionar os documentos de entrada, bem como classificar e limitar os resultados. Esse processo usa funções JavaScript personalizadas para executar o mapeamento e reduzir as operações, bem como a operação de finalização opcional. Embora o JavaScript personalizado ofereça grande flexibilidade em comparação com o pipeline de agregação, em geral, o map-reduce é menos eficiente e mais complexo que o pipeline de agregação.

Você pode ver exemplos neste link.

Pipeline de agregação
Por fim, o pipeline de agregação é a terceira forma de agregar os dados que o Mongo DB oferece. Ele é uma estrutura para agregação de dados modelada no conceito de pipelines de processamento de dados. Os documentos entram em um pipeline de vários estágios, que transforma os documentos em resultados agregados.

Para demostrar como funciona a pipeline, temos a seguinte chamada da função:

db.companies.aggregate([{$match:{founded_year:2004}},{$project:{_id:0,name:1,foudb.companies.aggregate([{$match:{founded_year:2004}},{$project:{_id:0,name:1,founded_year:1}}])

Lista com 5 documentos ordenados pelo nome, com apenas nome e ano de fundação, sendo o ano de fundação 2004

{$sort:{name:1}} ,​

{$limit:5} ​

])

Como podemos ver no esquema acima, a pipeline tem uma entrada que é transformada a cada etapa, sendo que a saída da etapa 1 é a entrada da etapa 2. Como exemplificado, as pipelines trabalham em etapas e várias operações podem ser executadas em sequência. Nelas, podemos utilizar os filtros ou outras operações nativas do MongoDB para obter o resultado desejado.

Dentre as operações possíveis nos estágios da pipeline temos os filtros, que funcionam como consultas, e transformações de documentos, que modificam a forma do documento de saída. Outras operações de pipeline oferecem ferramentas para agrupar e classificar documentos por campo ou campos específicos, bem como para agregar o conteúdo de matrizes, incluindo as matrizes de documentos.

Além disso, os estágios do pipeline podem usar operadores para tarefas, como calcular a média ou concatenar uma string. Os estágios do pipeline podem aparecer várias vezes, com exceção dos $out, $merge e $geoNear.

Para obter uma lista de todos os estágios disponíveis, verifique na documentação do MongoDB os estágios de pipeline de agregação.

O pipeline de agregação também pode usar índices para melhorar seu desempenho durante alguns de seus estágios, e possui uma fase de otimização interna. No exemplo a seguir, temos um banco de dados com diversos documentos com informações sobre empresas, com ano de fundação. Na expressão a seguir, fazemos o filtro pelo ano de (2004) e ordenamos pelo nome da empresa, mostrando os 5 primeiros resultados:

db.companies.aggregate([​

{$match: {founded_year: 2004}},​

{$project: {​

_id:0,​

name:1,​

founded_year:1​

}},​

{$sort:{name:1}} ,​

{$limit:5} ​

])​

Aqui temos alguns dos estágios de agregação disponíveis, com a descrição de suas funções:

$addFields: Adiciona novos campos para documentos. É semelhante à $project $addFields, reformula cada documento no fluxo, especificamente, adicionando novos campos aos documentos de saída que contêm os campos existentes nos documentos de entrada e os campos adicionados recentemente. $set é um alias para $addFields.

$collStats: Retorna estatísticas sobre uma coleção ou exibição.

$count: Retorna uma contagem do número de documentos neste estágio do pipeline de agregação.

$facet: Processa vários pipelines de agregação em um único estágio no mesmo conjunto de documentos de entrada. Permite a criação de agregações multifacetadas, capazes de caracterizar dados em várias dimensões ou facetas, em um único estágio.

$geoNear: Retorna um fluxo ordenado de documentos com base na proximidade de um ponto geoespacial. Incorpora a funcionalidade de $match, $sort e $limit para dados geoespaciais. Os documentos de saída incluem um campo de distância adicional e podem incluir um campo de identificador de local.

$graphLookup: Executa uma pesquisa recursiva em uma coleção. Para cada documento de saída, adiciona um novo campo de matriz que contém os resultados transversais da pesquisa recursiva para esse documento.

$group: Agrupa documentos de entrada por uma expressão identificadora especificada e aplica as expressões do acumulador, se especificadas, a cada grupo. Consome todos os documentos de entrada e produz um documento por cada grupo distinto. Os documentos de saída contêm apenas o campo identificador e, se especificado, campos acumulados.

$limit: Passa os primeiros n documentos não modificados para o pipeline em que n é o limite especificado. Para cada documento de entrada, gera um documento (para os primeiros n documentos) ou zero documento (após os primeiros n documentos).

$lookup: Executa uma associação externa à esquerda da outra coleção no mesmo banco de dados para filtrar documentos da coleção "unida" para processamento.

$match: Filtra o fluxo de documentos para permitir que apenas documentos correspondentes passem sem modificação para o próximo estágio do pipeline. $ match usa consultas padrão do MongoDB. Para cada documento de entrada, gera um documento (uma correspondência) ou zero documentos (sem correspondência).

$merge: Grava os documentos resultantes do pipeline de agregação em uma coleção. O estágio pode incorporar os resultados (inserir novos documentos, mesclar documentos, substituir documentos, manter documentos existentes, falhar na operação, processar documentos com um pipeline de atualização personalizado) em uma coleção de saída. Para usar o estágio $ merge, ele deve ser o último estágio no pipeline. Novo na versão 4.2.

$out: Grava os documentos resultantes do pipeline de agregação em uma coleção. Para usar o estágio $ out, ele deve ser o último estágio no pipeline.

$project: Remodela cada documento no fluxo, como adicionando novos campos ou removendo campos existentes. Para cada documento de entrada, gera um documento. Consulte também $ unset para remover os campos existentes.

$replaceWith: Substitui um documento pelo documento incorporado especificado. A operação substitui todos os campos existentes no documento de entrada, incluindo o campo _id. Especifique um documento incorporado no documento de entrada para promover o documento incorporado ao nível superior. $ replaceWith é um alias para o estágio $ replaceRoot.

$sample: Seleciona aleatoriamente o número especificado de documentos de sua entrada.

$set: Adiciona novos campos aos documentos. Semelhante a $ project, $ set reformula cada documento no fluxo; especificamente, adicionando novos campos aos documentos de saída que contêm os campos existentes nos documentos de entrada e os campos adicionados recentemente. $ set é um alias para o estágio $ addFields.

$skip: Ignora os primeiros n documentos em que n é o número de ignorado especificado e passa os documentos restantes sem modificação para o pipeline. Para cada documento de entrada, gera zero documentos (para os primeiros n documentos) ou um documento (se após os primeiros n documentos).

$sort: Reordena o fluxo de documentos por uma chave de classificação especificada. Somente a ordem muda; os documentos permanecem sem modificação. Para cada documento de entrada, gera um documento.

$sortByCount: Agrupa documentos recebidos com base no valor de uma expressão especificada e calcula a contagem de documentos em cada grupo distinto.

$unset: Remove / exclui campos dos documentos. $ unset é um alias para o estágio $ project que remove os campos.

$unwind: Desconstrói um campo de matriz dos documentos de entrada para produzir um documento para cada elemento. Cada documento de saída substitui a matriz por um valor do elemento. Para cada documento de entrada, gera n documentos em que n é o número de elementos da matriz e pode ser zero para uma matriz vazia.

Ficou alguma dúvida ou tem alguma observação? Deixe um comentário! Se você quiser aprender junto com a gente aqui na Concrete, é só dar uma olhada aqui e se candidatar a uma de nossas vagas. Vamos aprender juntos!

--

--