Este capítulo apresenta uma explicação detalhada da análise estatística do MongoDB, principalmente alcançada através do Aggregation Pipeline. É semelhante à declaração "group by" no SQL. No shell do MongoDB, a análise estatística é implementada usando a função db.collection.aggregate().

Tutorial prévio

MongoDB Aggregation Pipeline

Etapas gerais

  • Use $match para filtrar os dados alvo
  • Use $group para agrupar e calcular os dados
  • Use $sort para ordenar os resultados (opcional)

Dados de teste

Os dados na coleção orders são os seguintes

{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }

Função de agregação

db.collection.aggregate(pipeline) Explicação:

  • O pipeline recebe um parâmetro de array, onde cada elemento representa uma etapa de processamento.

Exemplo

db.orders.aggregate([
                     { $match: { status: "A" } },  // Primeira etapa
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },   // Segunda etapa
                     { $sort: { total: -1 } }  // Terceira etapa
                   ])

SQL equivalente

select sum(amount) as total from orders 
        where status="A" 
        group by cust_id 
        order by total desc

Etapa $match

Formato:

{ $match: { <query> } }

Explicação:

  • <query> Condições de consulta do MongoDB

Usado para definir condições de consulta. Se $match for ignorado, implica a consulta de todos os dados.

Dica: Se você não estiver familiarizado com a sintaxe de consulta do MongoDB, consulte os capítulos anteriores.

Etapa $group

Similar à cláusula group by no SQL, é usada para agrupar os dados e depois realizar uma série de cálculos estatísticos nos dados agrupados.

Uso básico do $group

Sintaxe:

{
  $group:
    {
      _id: <expressão>, // Condição de agrupamento, por exemplo: agrupar por qual campo
      <campo1>: { <acumulador1> : <expressão1> },  // Operação de agregação, você pode adicionar N operações de agregação
      ...
    }
 }

Explicação:

  • - Nome do indicador estatístico personalizado, pode ser N no total
  • - Função de agregação, similar a somatório, média e outras funções de agregação do SQL, a diferença é que as funções de agregação do MongoDB são nomeadas com o prefixo $, por exemplo: $sum, $avg
  • <expressão1> - Parâmetro da função de agregação, geralmente o valor do campo a ser contado, referenciando os campos do documento usando o formato "$nome do campo"

Exemplo:

db.orders.aggregate([
                     {
					 	$group: { 
							_id: "$cust_id",
							total: { $sum: "$amount" }, // Adiciona o primeiro indicador calculado total, usando o operador de soma $sum
							amount_avg: {$avg: "$amount"}  // Adiciona o segundo indicador calculado avg, usando o operador de cálculo de média $avg
						} 
					}
               ])

Saída:

{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }

SQL equivalente:

select 
	sum(amount) as  total,
	avg(amount) as amount_avg
from orders 
group by cust_id

Funções de Agregação do $group

As funções de agregação comumente utilizadas para o $group são as seguintes:

Operador Descrição Exemplo
$avg Calcular a média {$avg: "$amount"}
$sum Soma {$sum: "$amount"}
$max Valor máximo {$max: "$amount"}
$min Valor mínimo {$min: "$amount"}
$first Retorna dados após a agregação, o conteúdo do primeiro documento {$first: "$amount"}
$last Retorna dados após a agregação, o conteúdo do último documento {$last: "$amount"}
$push Retorna dados após a agregação { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet Retorna dados após a agregação, diferente do $push, pois remove duplicatas { $addToSet: "$amount" }

Exemplo de $push

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // Valores dos campos ord_date e amount
         }
     }
   ]
)

Saída

{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }

Exemplo de $addToSet

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all_amount: { $addToSet: "$amount" } // Retorna todos os valores distintos de amount
         }
     }
   ]
)

Saída

{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }

$sort:

A etapa $sort é normalmente colocada no final para classificar os dados agregados.

Formato:

{ $sort: { <campo1>: <ordem de classificação>, <campo2>: <ordem de classificação> ... } }

Explicação:

  • , - Os nomes dos campos a serem classificados, suporta múltiplos campos.
  • <ordem de classificação> - A direção da classificação, -1 para decrescente, 1 para crescente.

Exemplo:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } }
                   ])

Paginação de Agregados

Podemos implementar a paginação usando os operadores $limit e $skip.

Exemplo:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } },
					 { $limit: 5 }, // Limita o número de registros retornados, similar ao tamanho da página na paginação.
					 { $skip: 1 } // Pula um certo número de registros, similar ao deslocamento em SQL.
                   ])