Volver a MongoDB Básico

Pipeline de Agregación en MongoDB

Concepto del Pipeline

Cada etapa transforma documentos y pasa los resultados a la siguiente:

Colección → [$match] → [$group] → [$sort] → [$project] → Resultado

Etapas Principales

// $match — filtrar (usa índices, ponerlo primero) { $match: { estado: "activo", edad: { $gte: 18 } } } // $project — remodelar documentos { $project: { nombreCompleto: { $concat: ["$nombre", " ", "$apellido"] }, anio: { $year: "$creado_en" }, _id: 0 } } // $group — agregar { $group: { _id: "$categoria", total: { $sum: "$precio" }, promedio: { $avg: "$precio" }, conteo: { $sum: 1 }, maxPrecio: { $max: "$precio" }, productos: { $push: "$nombre" } } } // $sort, $limit, $skip { $sort: { total: -1 } } { $limit: 10 } { $skip: 20 }

$lookup (JOIN)

db.pedidos.aggregate([ { $lookup: { from: "clientes", localField: "clienteId", foreignField: "_id", as: "cliente" } }, { $unwind: "$cliente" }, { $project: { pedidoId: "$_id", total: 1, nombreCliente: "$cliente.nombre" } } ])

$unwind

// Deconstruir campo array db.publicaciones.aggregate([ { $unwind: "$etiquetas" }, { $group: { _id: "$etiquetas", conteo: { $sum: 1 } } }, { $sort: { conteo: -1 } } ])

$addFields y $bucket

// Agregar campos calculados { $addFields: { totalConIva: { $multiply: ["$total", 1.16] }, anio: { $year: "$fechaPedido" } } } // Agrupar en rangos { $bucket: { groupBy: "$precio", boundaries: [0, 50, 100, 200, 500], default: "500+", output: { conteo: { $sum: 1 }, promedio: { $avg: "$precio" } } } }

Ejemplo Real: Ingresos Mensuales

db.pedidos.aggregate([ { $match: { estado: "completado", creado_en: { $gte: new Date("2024-01-01") } } }, { $addFields: { mes: { $month: "$creado_en" }, anio: { $year: "$creado_en" } } }, { $group: { _id: { anio: "$anio", mes: "$mes" }, ingresos: { $sum: "$total" }, numPedidos: { $sum: 1 }, promedioP: { $avg: "$total" } } }, { $sort: { "_id.anio": 1, "_id.mes": 1 } }, { $project: { _id: 0, periodo: { $concat: [ { $toString: "$_id.anio" }, "-", { $toString: "$_id.mes" } ]}, ingresos: { $round: ["$ingresos", 2] }, numPedidos: 1, promedioP: { $round: ["$promedioP", 2] } } } ])

$facet (Múltiples Pipelines)

db.productos.aggregate([ { $match: { categoria: "Electrónica" } }, { $facet: { rangosPrecios: [ { $bucket: { groupBy: "$precio", boundaries: [0, 100, 500, 1000] } } ], topMarcas: [ { $group: { _id: "$marca", conteo: { $sum: 1 } } }, { $sort: { conteo: -1 } }, { $limit: 5 } ], totalResultados: [ { $count: "total" } ] } } ])