Explica cómo ejecutar subpipelines paralelos con $facet, clasificar valores con $bucket y construir respuestas con varias métricas desde una sola entrada.
$facet ejecuta varias subpipelines sobre el mismo conjunto de entrada y devuelve sus resultados dentro de un único documento. $bucket y $bucketAuto agrupan valores en rangos. Juntos permiten construir páginas con datos y metadata, histogramas y reportes multidimensionales.
Sin facet, la aplicación puede ejecutar una query para datos y otra para total. Eso permite optimizar y escalar cada operación por separado, pero son dos viajes y pueden observar estados distintos.
$facet produce ambas salidas desde la misma pipeline, aunque añade trabajo y memoria. No siempre es mejor: un count exacto puede ser mucho más costoso que obtener veinte documentos.
Un $facet como primer stage puede impedir uso eficiente de índices y hacer que cada rama reciba toda la colección. Coloca filtros selectivos y, cuando corresponda, un sort respaldado por índice antes.
Las subpipelines tienen límites de memoria y el documento final sigue sujeto al máximo BSON. allowDiskUse no elimina todos los límites específicos de facet. Verifica documentación de la versión objetivo.
No intentes devolver miles de resultados dentro de múltiples arrays en un solo documento.
Un histograma puede ocultar outliers si los rangos son demasiado amplios. $bucketAuto puede producir rangos poco intuitivos cuando hay muchos valores repetidos o distribuciones sesgadas.
Esta capacidad no sustituye automáticamente un motor de búsqueda especializado. Relevancia, análisis lingüístico y faceting a gran escala pueden pertenecer a MongoDB Search u otra herramienta.
Facet con count exacto obliga a recorrer todas las coincidencias para calcular total, aunque solo devuelva veinte items. En colecciones grandes considera:
hasNextPage con limit + 1;
count separado y cacheado;
estimaciones;
contador materializado;
total asíncrono;
omitir total.
La experiencia de usuario rara vez necesita un count exacto en cada request.
db.orders.aggregate([{$match:{
businessId,confirmedAt:{$gte: start,$lt: end },status:'confirmed'}},{$facet:{totals:[{$group:{_id:null,orders:{$sum:1},revenue:{$sum:'$total'},averageTicket:{$avg:'$total'}}}],byPaymentMethod:[{$group:{_id:'$payment.method',count:{$sum:1},revenue:{$sum:'$total'}}},{$sort:{revenue:-1}}],latestOrders:[{$sort:{confirmedAt:-1,_id:-1}},{$limit:5},{$project:{customer:1,total:1,confirmedAt:1}}]}}]);
Todas las ramas comparten tenant, periodo y estado. Si este dashboard se consulta constantemente, puede ser mejor materializar métricas.
$facet comparte una entrada entre múltiples análisis, pero duplica el trabajo específico de cada rama y concentra las salidas en un documento. $bucket ofrece rangos estables; $bucketAuto, exploración adaptativa. Úsalos con filtros tempranos, cardinalidad controlada y una necesidad real de resultados paralelos.
Comprueba lo aprendido
¿Qué ventaja y coste tiene $facet frente a dos queries?
¿Por qué debe existir $match antes?
¿Qué diferencia existe entre $bucket y $bucketAuto?