Filtrar documentos anidados con $redact

Resumen

El operador $redact en MongoDB te permite incluir o excluir partes completas de un documento, incluidos sus subdocumentos, según una condición lógica. Es una herramienta poderosa cuando necesitas filtrar contenido anidado dentro de un pipeline de agregación, algo que $match no resuelve con la misma profundidad.

¿Qué hace el operador $redact y en qué se diferencia de match?

Mientras $match filtra documentos completos según una condición, $redact actúa a nivel de estructura interna. Evalúa cada nivel del documento y decide si lo conserva o lo descarta antes de pasar a las siguientes etapas del pipeline.

¿Qué es $redact en MongoDB? Es un operador de agregación que evalúa una condición sobre cada documento y subdocumento, y decide si lo mantiene con $$KEEP o lo elimina con $$PRUNE.

Esto significa que si excluyes un campo en una etapa temprana, ese campo y todo lo que contiene ya no estará disponible en las etapas posteriores. Por eso conviene planear bien dónde lo colocas dentro del flujo.

¿Cómo se construye una consulta con $redact paso a paso?

El reto consiste en omitir todas las propiedades de Airbnb cuya calificación esté por debajo de 90. Para lograrlo, vas a construir una condicional explícita usando $cond, porque MongoDB no interpreta automáticamente un if suelto como estructura condicional.

¿Qué estructura debe tener la condición?

La lógica se arma con tres bloques: la condición que evalúas, qué hacer si se cumple y qué hacer si no. En este caso, la referencia es el campo review_scores.review_scores_rating, que vive dentro de un subobjeto.

javascript db.listingsAndReviews.aggregate([ { $redact: { $cond: { if: { $gte: ["$review_scores.review_scores_rating", 95] }, then: "$$KEEP", else: "$$PRUNE" } } }, { $count: "total" } ])

Aquí $$KEEP mantiene el documento cuando la calificación es igual o mayor a 95, y $$PRUNE lo elimina cuando no cumple. Son variables especiales del sistema que $redact reconoce de forma nativa.

¿Por qué es necesario envolver la condición en $cond?

Si escribes if, then y else directamente, MongoDB lanza un error. El operador $cond es el que le dice al motor que estás trabajando con una condicional, así que debe contener todo el bloque de evaluación.

¿Cuál es la diferencia entre $$KEEP y $$PRUNE? $$KEEP conserva el documento o subdocumento actual, mientras que $$PRUNE lo descarta junto con todo lo que contiene dentro.

¿Cómo verificar el resultado del pipeline con un contador?

Para medir el impacto del filtro, agregar una etapa $count al final del pipeline es la forma más directa de saber cuántos documentos sobrevivieron a la condición.

En la muestra de Airbnb usada en la clase, el resultado es claro:

  • La colección original contiene aproximadamente 5600 documentos.
  • Después de aplicar $redact con el umbral de 95, quedan 2287 documentos.
  • Eso representa cerca del 40% de la muestra original.

Este contador te permite validar rápidamente que la condición está bien escrita y que el campo anidado se está leyendo correctamente.

¿Cuándo conviene usar $redact y cuándo es mejor evitarlo?

Hay dos recomendaciones prácticas que vale la pena tener presentes antes de meter $redact en producción.

  • Cuidado con la propagación: una vez que excluyes un campo en una etapa, ese campo desaparece para todas las etapas siguientes. Si en otra parte del pipeline necesitas ese dato, ya no lo vas a tener.
  • Costo en recursos: $redact es más costoso computacionalmente que $match. Si tu filtro se puede resolver con $match, esa es la opción más eficiente.
  • Casos ideales: úsalo cuando necesitas filtrar contenido anidado a varios niveles, controlar permisos por documento o aplicar reglas que $match no puede expresar.

La regla general es simple: si puedes resolverlo con $match, hazlo con $match. Reserva $redact para los casos donde la lógica de inclusión y exclusión vive dentro de la estructura del documento.

¿En qué otro escenario crees que $redact resolvería mejor una consulta que $match? Compártelo en los comentarios.