¿Qué es una pipeline de agregación?
El Aggregation Framework transforma datos en MongoDB. Funciona como una pipeline donde cada etapa recibe documentos, los procesa y los pasa a la siguiente.
db.coleccion.aggregate([ // siempre recibe array []
{ $etapa1 },
{ $etapa2 },
{ $etapa3 }
])
Regla importante: Los campos del documento dentro del aggregate siempre llevan
$:"$price","$address.country".
Ejercicio 22 — $group para Precio Promedio por País
Calcular el precio promedio de los listings por cada address.country.
use('sample_airbnb');
db.listingsAndReviews.aggregate([
{
$group: {
_id: "$address.country",
precio_promedio: { $avg: "$price" }
}
}
])
¿Qué aprendemos aquí?
_iden$groupes obligatorio — define por qué campo agrupar$avgcalcula el promedio del campo indicado- Los documentos sin el campo
priceretornannullen el promedio - Los documentos insertados por nosotros sin
address.countryaparecen con_id: null
Acumuladores disponibles en $group
| Acumulador | Función |
|---|---|
$sum: 1 | Contar documentos |
$sum: "$campo" | Sumar valores |
$avg: "$campo" | Promedio |
$min: "$campo" | Valor mínimo |
$max: "$campo" | Valor máximo |
Ejercicio 24 — $group y $sort por property_type
Calcular la cantidad de listings por property_type y ordenar de mayor a menor.
use('sample_airbnb');
db.listingsAndReviews.aggregate([
{
$group: {
_id: "$property_type",
total: { $sum: 1 }
}
},
{
$sort: { total: -1 }
}
])
¿Qué aprendemos aquí?
$sum: 1cuenta un documento por cada uno que pasa por el grupo- No necesitas
$matchsi quieres procesar todos los documentos $sortdespués del$groupordena los resultados calculados
Resultado esperado
{ _id: 'Apartment', total: 3626 }
{ _id: 'House', total: 606 }
{ _id: 'Condominium', total: 399 }
// ...
Ejercicio 26 — Pipeline Complejo con Review Scores
Filtrar listings con al menos 10 reviews y calcular el promedio de review_scores_rating.
use('sample_airbnb');
db.listingsAndReviews.aggregate([
{
$match: {
number_of_reviews: { $gt: 10 }
}
},
{
$group: {
_id: null,
promedio: { $avg: "$review_scores.review_scores_rating" }
}
}
])
¿Qué aprendemos aquí?
$matchal inicio filtra antes de agrupar — más eficiente_id: nullagrupa todos los documentos en un solo resultado- Los campos anidados en aggregate también usan dot notation con
$:"$review_scores.review_scores_rating"
Resultado esperado
{ _id: null, promedio: Double('93.78787878787878') }
Ejercicio 28 — $lookup Simulación de JOIN
Describir un pipeline que usaría $lookup si existiera una colección hosts para unir listings con la información del anfitrión por host.host_id.
use('sample_airbnb');
// Ejercicio teórico — la colección hosts no existe en sample_airbnb
db.listingsAndReviews.aggregate([
{
$lookup: {
from: "hosts",
localField: "host.host_id",
foreignField: "host_id",
as: "informacion_host"
}
},
{
$project: {
name: 1,
"host.host_name": 1,
informacion_host: 1,
_id: 0
}
}
])
¿Qué aprendemos aquí?
$lookupes el equivalente al JOIN en SQL- Realiza un left outer join entre dos colecciones
- El resultado se guarda como un array en el campo
as
Estructura de $lookup
| Parte | Qué hace |
|---|---|
from | La colección a unir |
localField | Campo en la colección actual |
foreignField | Campo en la otra colección |
as | Nombre del array resultante |
Restricción:
$lookupsobre colecciones sin índice enforeignFieldgenera consultas muy lentas en producción.
Ejercicio 30 — Análisis por Fecha con $year
Filtrar listings con last_review registrada y contar cuántos tuvieron su última revisión en cada año.
use('sample_airbnb');
db.listingsAndReviews.aggregate([
{
$match: {
last_review: { $exists: true }
}
},
{
$group: {
_id: { $year: "$last_review" },
total: { $sum: 1 }
}
},
{
$sort: { _id: 1 }
}
])
¿Qué aprendemos aquí?
$exists: truefiltra documentos que tienen el campo — necesario porque$yearfalla sobre campos nulos$yearextrae el año de un campo de tipo fecha$yearva dentro del_iddel$grouppara agrupar por año$sort: { _id: 1 }ordena los años de menor a mayor
Resultado esperado
{ _id: 2012, total: 5 }
{ _id: 2013, total: 2 }
{ _id: 2014, total: 14 }
{ _id: 2015, total: 97 }
{ _id: 2016, total: 212 }
{ _id: 2017, total: 318 }
{ _id: 2018, total: 1264 }
Operadores de fecha disponibles
| Operador | Función |
|---|---|
$year | Extrae el año |
$month | Extrae el mes |
$dayOfMonth | Extrae el día |
$dateToString | Formatea la fecha como string |