Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tutosrive/db-nosql-2026-1/llms.txt

Use this file to discover all available pages before exploring further.

El pipeline de agregación es el mecanismo más poderoso de MongoDB para transformar y analizar datos. A diferencia de find(), que simplemente filtra y proyecta documentos, el pipeline permite encadenar múltiples operaciones: agrupar por campo, calcular promedios, renombrar campos, hacer joins entre colecciones y mucho más. Cada etapa recibe el resultado de la anterior y entrega una salida transformada a la siguiente, formando una tubería de procesamiento.

El Pipeline de Agregación

El método aggregate() recibe un arreglo de etapas. Los documentos de la colección entran por la primera etapa, se transforman, y el resultado fluye hacia la siguiente.
Colección


[ $match ]  ──▶  filtra documentos


[ $group ]  ──▶  agrupa y calcula acumuladores


[ $project ] ─▶  selecciona/renombra campos


[ $sort ]   ──▶  ordena el resultado


[ $limit ]  ──▶  limita el número de resultados


  Salida
El orden de las etapas importa. Por ejemplo, colocar $match al principio del pipeline reduce el número de documentos que procesan las etapas siguientes, mejorando el rendimiento considerablemente.

Etapas Principales

EtapaDescripción
$matchFiltra documentos (como find)
$groupAgrupa por un campo y calcula acumuladores
$projectSelecciona, renombra o calcula campos
$sortOrdena documentos
$limitLimita el número de resultados
$skipSalta documentos
$unwindDescompone arreglos en documentos individuales
$lookupJOIN entre colecciones

$group: Agrupar Documentos

La etapa $group es el núcleo de la agregación. Agrupa los documentos por el valor de _id y calcula acumuladores para cada grupo.
Pista clave: Cuando el enunciado dice “por cada” o “para cada”, normalmente se necesita un $group.

Ejemplo base: Contar personas por género

db.personas.aggregate([
  {
    $group: {
      _id: "$gender",
      total: { $sum: 1 }
    }
  }
])

Proyectar la salida con $project

Para controlar los nombres de los campos en el resultado final, se combina $group con $project:
// Salida con campos: genero y total (sin _id)
db.personas.aggregate([
  { $group: { _id: "$gender", total: { $sum: 1 } } },
  { $project: { _id: 0, genero: "$_id", total: 1 } },
  { $sort: { total: 1 } }
])

Acumuladores en $group

Los acumuladores son funciones que calculan un valor a partir de todos los documentos del mismo grupo.
AcumuladorDescripciónEjemplo
$sumSuma{ $sum: 1 } o { $sum: "$campo" }
$avgPromedio{ $avg: "$dob.age" }
$maxValor máximo{ $max: "$dob.age" }
$minValor mínimo{ $min: "$dob.age" }
$pushArreglo con todos los valores del grupo{ $push: "$nombre" }
$firstPrimer valor del grupo{ $first: "$nombre" }
$lastÚltimo valor del grupo{ $last: "$nombre" }

Ejercicios de Agregación

Los siguientes ejercicios fueron trabajados en clase con la colección personas. Cada uno introduce una nueva combinación de etapas.

Ejercicio 1 — Top 50 nacionalidades con más personas

db.personas.aggregate([
  {
    $group: {
      _id: "$nat",
      total: { $sum: 1 }
    }
  },
  { $sort: { total: -1 } },
  { $limit: 50 }
])

Ejercicio 2 — Top 50 con proyección (nacionalidad y conteo)

db.personas.aggregate([
  {
    $group: {
      _id: "$nat",
      total: { $sum: 1 }
    }
  },
  { $sort: { total: -1 } },
  {
    $project: {
      _id: 0,
      nacionalidad: "$_id",
      conteo: "$total"
    }
  },
  { $limit: 50 }
])

Ejercicio 3 — Top 5 ciudades con menos personas, ordenadas

Primero, las ciudades con menor número de personas:
db.personas.aggregate([
  {
    $group: {
      _id: "$location.city",
      total: { $sum: 1 }
    }
  },
  { $sort: { total: 1 } },
  { $limit: 5 }
])
Con doble ordenación (ciudad alfabéticamente y total ascendente):
db.personas.aggregate([
  {
    $group: {
      _id: "$location.city",
      total: { $sum: 1 }
    }
  },
  { $sort: { _id: 1, total: 1 } },
  { $limit: 5 }
])

Ejercicio 4 — Número de personas por género y nacionalidad

db.personas.aggregate([
  {
    $group: {
      _id: {
        nacionalidad: "$nat",
        genero: "$gender"
      },
      totalPersonas: { $sum: 1 }
    }
  },
  { $sort: { "_id.nacionalidad": 1, genero: 1 } }
])

Ejercicio 5 — Promedio de edades por género y nacionalidad, top 5

db.personas.aggregate([
  {
    $group: {
      _id: {
        genero: "$gender",
        nacionalidad: "$nat"
      },
      promedio: { $avg: "$dob.age" }
    }
  },
  { $sort: { promedio: -1 } },
  {
    $project: {
      _id: 0,
      genero: "$_id.genero",
      nacionalidad: "$_id.nacionalidad",
      promedio: 1
    }
  },
  { $limit: 5 }
])

Ejercicio 6 — Filtrar mayores de 20, agrupar por género y ciudad con múltiples acumuladores

db.personas.aggregate([
  { $match: { "dob.age": { $gt: 20 } } },
  {
    $group: {
      _id: { genero: "$gender", ciudad: "$location.city" },
      promedioEdadPersona: { $avg: "$dob.age" },
      promedioEdadRegistro: { $avg: "$registered.age" },
      mayorEdad: { $max: "$dob.age" },
      menorEdad: { $min: "$dob.age" },
      totalLocal: { $sum: 1 }
    }
  },
  { $sort: { promedioEdadRegistro: -1 } },
  { $limit: 30 }
])

Ejercicio 7 — Por nacionalidad y estado, total de personas ≥ 10

Este ejercicio usa $match después de $group para filtrar grupos que no cumplan una condición de acumulador.
db.personas.aggregate([
  {
    $group: {
      _id: {
        nacionalidad: "$nat",
        estado: "$location.state"
      },
      total: { $sum: 1 }
    }
  },
  { $match: { total: { $gte: 10 } } },
  {
    $project: {
      _id: 0,
      nacionalidad: "$_id.nacionalidad",
      estado: "$_id.estado",
      total: 1
    }
  }
])
El $match post-$group filtra sobre el resultado del grupo (por ejemplo, sobre total). El $match pre-$group filtra los documentos originales antes de agrupar. Ambos usos son válidos y frecuentes.

$project: Proyectar en el Pipeline

La etapa $project dentro del pipeline tiene más capacidades que la proyección de find(): permite renombrar campos, calcular expresiones y concatenar strings.

Proyección básica con campos calculados

db.personas.aggregate([
  {
    $project: {
      _id: 0,
      nombre: { $concat: ["$name.first", " ", "$name.last"] },
      ciudad: "$location.city",
      email: "$email",
      estado: "$location.state",
      pais: "$nat",
      edad: "$dob.age"
    }
  },
  { $limit: 10 }
])

Proyección con edad de registro y descripción de la localización

db.personas.aggregate([
  {
    $project: {
      _id: 0,
      nombre: { $concat: ["$name.first", " ", "$name.last"] },
      email: "$email",
      estado: "$location.state",
      edad_registro: "$registered.age",
      descripcion_locacion: "$location.timezone.description"
    }
  },
  { $limit: 25 }
])

$match con Condiciones

$match al inicio del pipeline actúa igual que find(), pero al estar dentro del pipeline su resultado fluye hacia las etapas siguientes.

Ejercicio — Proyectar personas de género masculino entre 15 y 20 años

Enunciado: Proyectar en un solo campo el título de la persona y el apellido en un campo llamado nombre para las personas de sexo masculino cuya edad de registro esté entre 15 y 20 años inclusive, límite de 500, ordenados por el apellido ascendentemente.
db.personas.aggregate([
  { $match: { gender: "male", "dob.age": { $gte: 15, $lte: 20 } } },
  {
    $project: {
      _id: 0,
      nombre: { $concat: ["$name.title", " ", "$name.last"] },
      edad: "$dob.age",
      nat: 1
    }
  },
  { $sort: { apellido: 1 } },
  { $limit: 500 }
])

Build docs developers (and LLMs) love