Juan Camilo Noreña López
++Expresive operator++ ($expr) : Sirve para comparar valores en el mismo documento. Nota: poner atención a la sintaxis cuando se usa este operador.
El operador $expr en MongoDB te permite comparar dos campos del mismo documento dentro de una consulta, algo que los operadores tradicionales como $gt o $eq no resuelven solos. Si trabajas con datos financieros, métricas de uso o cualquier dataset donde necesites cruzar atributos internos, este operador te abre la puerta a queries mucho más potentes.
Qué es el expressive operator y cuándo usarlo
El $expr es un operador de MongoDB que habilita el uso de expresiones de aggregation dentro de un find normal. Su valor real aparece cuando dejas de comparar contra un número fijo y empiezas a comparar campos entre sí.
Imagina un dataset de presupuestos mensuales con dos atributos: budget (lo planeado) y spend (lo gastado). Con un $gt: 100 solo filtras gastos mayores a cien. Pero la pregunta interesante es otra: ¿cuáles presupuestos se pasaron? Para responderla necesitas comparar spend contra budget en el mismo documento, y ahí entra $expr [01:50].
¿Qué hace el operador $expr en MongoDB? Permite usar expresiones de aggregation dentro de un find para comparar campos del mismo documento entre sí, no solo contra valores fijos.
Cómo se escribe una consulta con $expr
La sintaxis cambia respecto a un find tradicional. Cuando usas $expr, el signo $ deja de ser solo un marcador de operador y pasa a referenciar un campo del documento.
Ejemplo para detectar presupuestos sobregirados:
javascript db.monthly_budget.find({ $expr: { $gt: ["$spend", "$budget"] } })
Aquí "$spend" y "$budget" no son strings: son referencias a los campos del documento. El resultado devuelve solo los registros donde el gasto superó el presupuesto, por ejemplo 450 sobre 400, 150 sobre 100 y 650 sobre 200 [03:30].
Por qué $expr cambia la forma de hacer queries
La diferencia clave es que abandonas la comparación contra valores estáticos. En lugar de preguntar “¿qué documentos tienen spend mayor a 100?”, puedes preguntar “¿qué documentos tienen spend mayor a su propio budget?”. Esa pregunta es imposible de responder con un $gt clásico.
Esto se vuelve útil en escenarios como:
Ejemplo con la colección trips de bicicletas
Usando el dataset sample_training.trips, que contiene viajes de una app de bicicletas en Nueva York, puedes responder una pregunta concreta: ¿cuántos usuarios tomaron una bici, dieron una vuelta y la devolvieron en la misma estación?
La consulta compara start_station_id con end_station_id:
javascript db.trips.find({ $expr: { $eq: ["$start_station_id", "$end_station_id"] } }).count()
El resultado es 316 viajes que iniciaron y terminaron en el mismo punto [06:40]. Sin $expr tendrías que traer los documentos a tu aplicación y filtrarlos manualmente.
Cómo combinar $expr con operadores lógicos
Puedes encadenar $expr con $and para responder preguntas más específicas. Por ejemplo: ¿cuántos viajes empezaron y terminaron en la misma estación y además duraron más de 1200 segundos?
Aquí aparece un detalle importante: una vez que entras al modo expresivo, todos los operadores internos deben seguir la sintaxis de array con dos argumentos. Si intentas mezclar la sintaxis clásica { trip_duration: { $gt: 1200 } } dentro de un $expr, MongoDB lanza un error indicando que el operador esperaba dos argumentos.
La forma correcta:
javascript db.trips.find({ $expr: { $and: [ { $eq: ["$start_station_id", "$end_station_id"] }, { $gt: ["$trip_duration", 1200] } ] } }).count()
Este query devuelve 173 viajes que cumplen ambas condiciones [09:30].
¿Por qué $expr exige sintaxis de array? Porque opera con expresiones de aggregation, donde cada operador recibe sus argumentos como una lista ordenada:
[campo, valor]o[campoA, campoB].
Regla práctica al usar $expr
Cuando entras al modo expresivo, ya no puedes volver a la sintaxis clásica dentro del mismo bloque. Toda comparación tiene que escribirse así: operador, atributo precedido de $, y el segundo argumento, que puede ser un valor fijo o otro campo del documento. Esa flexibilidad de comparar campo contra campo es la verdadera ganancia.
Dominar $expr te permite mover lógica que antes vivía en tu backend hacia la consulta misma, reduciendo transferencia de datos y simplificando el código de aplicación. ¿En qué query de tu proyecto reemplazarías un filtro manual por un $expr? Cuéntalo en los comentarios.
otra forma de hacer la misma consulta
use("sample_training") db.trips.find({ $and: [ {$expr: { $eq: ["$start station id", "$end station id"] }}, {tripduration: { $gte: 1200 }} ] }).count()
también podemos hacerlo con el $and implícito de esta forma
db.trips.find({ tripduration: { $gte: 1200 }, $expr: { $eq: ["$start station id", "$end station id"] } })
Juan Camilo Noreña López
++Expresive operator++ ($expr) : Sirve para comparar valores en el mismo documento. Nota: poner atención a la sintaxis cuando se usa este operador.
Federico Bisignano
use ("sample_training") // db.trips.find({ // $expr: { // $eq: ["$start station id", "$end station id"] // } // }).count() db.trips.find({ $expr: { $and: [ {$eq: ["$start station id", "$end station id"]}, { $gte: ["$tripduration", 1200]} //{ tripduration: {$gte: 1200}} ] } }).count()
Ronaldo Jiménez
// $expr se utiliza para comparar campos de un documento use('football'); db.scorers.find({ $expr: { $gte: ['$goles', '$partidos_jugados'] } });
Jessica Placencio
$expr es un operador de MongoDB que permite utilizar expresiones de agregación dentro de una consulta (find). Gracias a él puedes realizar comparaciones entre campos, operaciones matemáticas, operadores lógicos y otras expresiones de agregación para decidir si un documento cumple la condición.
Luis Santiago Cortés Hernández
¿Cómo lo puedo organizar de mayor a menor?
db.trips.find({ $expr: { $and: [ { $eq: ["$start station id","$end station id"]}, { $gte: [ "$tripduration",1200 ]} ] } })
Francisco Ponce
Andrea Lopez
db.trips.find({ $expr: { $and: [ { $eq: ["$start station id", "$end station id"] }, { $gte: ["$tripduration", 1200] } ] } }).sort({ tripduration: -1 })
Roberto Shirásago Domínguez
Genial:use("platzi_store")
use("platzi_store") // 1.1.- Buscar los documentos donde el campo spent sea mayor o igual a 100 db.monthlyBudget.find({ spent: {$gte: 100} }) // 1.2.- Ahora usando el operador expresivo $expr db.monthlyBudget.find({ $expr: { $gte: ["$spent", 100] } }) // 2.- Buscar los documentos donde el campo spent sea mayor o igual al campo budget db.monthlyBudget.find({ $expr: { $gte: ["$spent", "$budget"] // Busqueda entre campos } }) // 3.- Buscar los documentos donde el campo spent igual al campo budget db.monthlyBudget.find({ $expr: { $eq: ["$spent", "$budget"] // Busqueda entre campos } }) //4.- Buscar los documentos donde el campo spent sea igual al campo budget y mayor o igual a 100 db.monthlyBudget.find({ $expr: { $and: [ {$gte: ["$spent", "$budget"]}, {$gte: ["$spent", 100]} ] } })
Rafael Emigdio Mendoza
/** * ? Busca los documentos donde: * * La estación de inicio sea igual a la estación de destino * * La duración del viaje sea mayor a 1200 * * El tipo de usuario sea Costumer * * El año de nacimiento sea >= a 1980 */ use("sample_training"); db.trips.find({ $expr: { $and: [ { $eq: ["$start station id", "$end station id"] }, { $gte: ["$tripduration", 1200] }, { $eq: ["$usertype", "Costumer"] }, { $gte: ["$birth year", 1980] }], }, });
Si no mal recuerdo, hay un método sort en mongodb.
db.trips.find({ $expr: { $and: [ { $eq: ["$start station id", "$end station id"] }, { $gte: ["$tripduration", 1200] } ] } }).sort({ tripduration: -1 })
Donde el -1 los ordenará de manera descendente con base en el campo tripduration. Solo faltaría probar la query.