Este capítulo presenta una explicación detallada del análisis estadístico de MongoDB, que se logra principalmente a través del Aggregation Pipeline. Es similar a la instrucción "group by" en SQL. En la shell de MongoDB, el análisis estadístico se implementa utilizando la función db.collection.aggregate().

Tutorial preliminar

Tubería de agregación de MongoDB

Pasos generales

  • Use $match para filtrar los datos objetivos
  • Use $group para agrupar y calcular los datos
  • Use $sort para ordenar los resultados (opcional)

Datos de prueba

Los datos en la colección orders son los siguientes

{ _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 }

Función de agregación

db.collection.aggregate(pipeline) Explicación:

  • El pipeline toma un parámetro de array, donde cada elemento representa una etapa de procesamiento.

Ejemplo

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

Equivalente en SQL

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

Etapa $match

Formato:

{ $match: { <consulta> } }

Explicación:

  • <consulta> condiciones de consulta de MongoDB

Se utiliza para establecer condiciones de consulta. Si se ignora $match, implica la consulta de todos los datos.

Consejo: Si no está familiarizado con la sintaxis de consulta de MongoDB, consulte los capítulos anteriores.

Etapa $group

Similar a la cláusula group by en SQL, se utiliza para agrupar los datos y luego realizar una serie de cálculos estadísticos sobre los datos agrupados.

Uso básico de $group

Sintaxis:

{
  $group:
    {
      _id: <expresión>, // Condición de agrupación, por ejemplo: agrupar por qué campo
      <campo1>: { <acumulador1> : <expresión1> },  // Operación de agregación, se pueden agregar N operaciones de agregación
      ...
    }
 }

Explicación:

  • - Nombre del indicador estadístico personalizado, puede ser N en total
  • - Función de agregación, similar a sum, avg y otras funciones de agregación de SQL, la diferencia es que las funciones de agregación de MongoDB tienen un nombre con $ como prefijo, por ejemplo: $sum, $avg
  • <expresión1> - Parámetro de la función de agregación, generalmente el valor del campo a contar, haciendo referencia a los campos del documento utilizando el formato "$nombre del campo"

Ejemplo:

db.orders.aggregate([
                     {
					 	$group: { 
							_id: "$cust_id",
							total: { $sum: "$amount" }, // Agrega el primer indicador calculado total, usando el operador de suma $sum
							amount_avg: {$avg: "$amount"}  // Agrega el segundo indicador calculado avg, usando el operador de cálculo promedio $avg
						} 
					}
               ])

Salida:

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

Equivalente en SQL:

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

Funciones de Agregación $group

Las funciones de agregación comúnmente utilizadas para $group son las siguientes:

Operador Descripción Ejemplo
$avg Calcular el promedio {$avg: "$amount"}
$sum Suma {$sum: "$amount"}
$max Valor máximo {$max: "$amount"}
$min Valor mínimo {$min: "$amount"}
$first Devuelve datos después de agrupar, el contenido del primer documento {$first: "$amount"}
$last Devuelve datos después de agrupar, el contenido del último documento {$last: "$amount"}
$push Devuelve datos después de agrupar { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet Devuelve datos después de agrupar, diferente a $push ya que elimina duplicados { $addToSet: "$amount" }

Ejemplo de $push

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

Salida

{ "_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 } ] }

Ejemplo de $addToSet

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

Salida

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

$sort:

La etapa $sort se coloca típicamente al final para ordenar los datos agregados.

Formato:

{ $sort: { <campo1>: <orden>, <campo2>: <orden> ... } }

Explicación:

  • , - Los nombres de los campos a ordenar, admite múltiples campos.
  • - La dirección de la clasificación, -1 para descendente, 1 para ascendente.

Ejemplo:

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

Paginación de Agregados

Podemos implementar la paginación usando los operadores $limit y $skip.

Ejemplo:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } },
					 { $limit: 5 }, // Limita el número de registros devueltos, similar al tamaño de página en paginación.
					 { $skip: 1 } // Omite cierta cantidad de registros, similar al desplazamiento en SQL.
                   ])