Funciones de agregación

Introducción

Cuando hablamos de agregación, estamos hablando del equivalente de hacer sentencias en sql que contengan “count(*)” y “group by”. Por ejemplo, si queremos encontrar el número de jugadores por categoría en una colección que tiene la siguiente forma:

Realizaríamos la siguiente consulta:

Lo primero que vemos es la sentencia “aggregate” que recibe un array de objetos. En este caso, la primera clave es “$group” para indicar que queremos agrupar por “$categoria”, asociamos eso en la propiedad “_id”. La segunda clave del objeto, “num_jugadores” es el nombre que se mostrará en el resultado y como parámetro indicamos que queremos la suma de los elementos.

Tuberías (pipeline)

Como hemos visto, la función de agregación recibe un array de objetos.

Cada objeto es una operación que se realiza con los datos y el resultado de dicha operación, es la entrada de la siguiente. Se pueden enlazar las siguientes funciones de agregación:

  • $project → selección → 1:1
  • $match → filtra → n:1
  • $group → agregación → n:1
  • $sort → ordenación → 1:1
  • $skip → salta → n:1
  • $limit → limita → n:1
  • $unwind → joint → 1:n

Vamos a ver otro ejemplo, supongamos que tenemos lo siguiente:

Cuantos documentos devolverá el resultado de aplicar la siguiente función:

El resultado es: 2, ya que está agrupando por el valor “c” y únicamente hay dos valores diferentes (el 1 y el 2).

Agrupando por más de un valor

Anteriormente hemos visto los elementos agrupados por una propiedad. Del mismo modo, se pueden agrupar por varias propiedades. Vamos a ver un ejemplo, dada la siguiente colección:

Vamos a aplicar la siguiente función de agregación:

Bien, como podemos ver, estamos agrupando por 3 valores, a, b y c. Los literales “pora”, “porb” y “porc” se utilizan para mostrar el resultado, podría ser cualquier etiqueta. ¿Cuantos documentos son devueltos? La solución es 4, ya que se repiten los valores a b y c en los documentos con ids 2, 4 y 6

Usando un documento como _id

Hasta ahora hemos visto los documentos con un _id que consta de una clave, aunque se puede definir el id como un documento complejo:

Expresiones que se pueden usar en las funciones de agregación

Cuando usamos “$group”, podemos usar una serie de operaciones. Hemos visto la operación “$sum” en el primer ejemplo que aparece en este tema, pero existen algunos más:  

  • $sum → a 1, cuenta los elementos. Con otros valores, los suma con cada uno que encuentra
  •  $avg → media
  •  $min → el menor
  •  $max → el mayor
  •  $push → en arrays [] → Añade valores
  •  $addToSet → en arrays [] → Añade valores, pero solo una vez
  •  $first → el primer elemento → Hay que usar $sort para ordenar
  •  $last → el primer elemento → Hay que usar $sort para ordenar

Vamos a ver estas operaciones a continuación.

1. $sum

Vamos a ver un ejemplo, en el que agrupamos por equipo, y sumamos los goles de todos los jugadores del mismo equipo:

2. $avg

La media, es exactamente igual. Vamos a ver un ejemplo, en el que agrupamos por equpo, y calculamos la media de goles:

3. $addToSet

Supongamos que tenemos una lista de equipos de este tipo:

En el caso de que queramos agrupar por un elemento, como por ejemplo “equipo” y crear en el resultado una nueva propiedad que sea un array que contenga cada una de las categorías en las que juega. Realizaríamos lo siguiente:

El resultado será un array de objetos de este tipo:

4. $push

Este caso es idéntico al anterior, solo que en lugar de poner $addToSet, se pone $push:

El resultado será un array de objetos similar al anterior, solo que con todos los elementos que haya, aunque estén repetidos:

5. $max y $min

Siguiendo con el ejemplo de los equipos, vamos a consultar, cual es el mayor número de goles que ha marcado un jugador en cada equipo:

El resultado sería similar a lo siguiente:

6. Agrupamiento doble $group

Como hemos comentado antes, se puede hacer “pipeline” es deccir, enchufar el resultado de una agregación a la siguiente, por lo tanto, podremos agrupar por un criterio y el resultado volverlo a agrupar por otro, por ejemplo, dada la siguiente colección:

Podemos hacer lo siguiente:

El resultado sería el siguiente: 52 y 22 es decir, primero agrupamos por a y b y nos quedamos el mayor, lo que nos deja 54, 52, 22 y 97 y luego eso lo agrupamos unicamente por a, y nos quedamos con el mínimo, lo que nos da el resultado.

Proyección $project

Continuamos con las siguientes etapas del pipeline, hemos visto la función de agregación $group y ahora vamos a ver la proyección. Con $proyect podemos hacer cosas como eliminar claves, añadir nuevas claves, substituir una clave por otra, usar funciones simples sobre claves, como $toUpper, $toLower, $add, $multiply. Como se ha comentado, es una operación de 1:1, vamos a ver un ejemplo:

Dada la siguiente colección:

Escribir la función de agregación que transforme los datos de modo que queden así:

La solución es la siguiente:

Con 0 indicamos los que queremos que no aparezcan y con 1 los que queremos que se muestren.

$match

La siguiente etapa que vamos a ver es $match, que actúa a modo de filtro. Es parecido a un select, vamos a verlo un ejemplo:

Seleccionar los pueblos que tienen más de 1000 habitantes:

$sort

Sirve para ordenar, dicha ordenación se realiza en memoria. Por ejemplo, para ordenar los pueblos, por nombre y provincia de manera ascendente:

$limit y $skip

Para que tenga sentido usar esto, antes tendríamos que ordenar. Del mismo modo, lo que tiene sentido es que primero ejecutemos $skip, y luego $limit. Un ejemplo de uso en el pipeline, es el siguiente:

$first y $last

Recuperan el primer o el último elemento. Tiene sentido cuando están ordenados los datos. Vamos a ver un ejemplo:

Dada la colección:

Cual sería el valor de “c” como resultado de esta función de agregación:

El resultado sería 84

$unwind

Cuando en un documento tenemos un array y queremos agrupar por algún elemento del array, tenemos que hacer un join del objeto respecto del array, por ejemplo, supongamos que tenemos:

Si hacemos $unwind: “$c” tendríamos:

El caso contrario a hacer $unwind, sería el caso que hemos visto con $push. Por otra parte, si el objeto tiene dos arrays, se puede hacer un doble $unwind en el pipeline: {$unwind: $talla}, {$unwind: $color} lo que nos daría el producto cartesiano de los dos arrays.

Mapeo entre SQL y agregación y ejemplos SQL

En la documentación oficial de mongodb, tenemos una comparativa de las funciones de agregación con su equivalente en sql, así como ejemplos de código: Aquí

Límites en la agregación

Los límites en la agregación son los siguientes:

  • El resultado no puede superar los 16Mb
  • No se puede usar más del 10% de la memoria de la máquina
  • Puede dar problemas en entornos distribuidos

Aquí terminamos con este artículo, en el siguiente artículo hablaremos sobre fragmentación y replicación fragmentacio y replicacion

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *