Carlos Orejuela
Para expresar el precio de dólares a euros y truncando el resultado a 2 decimales:
[ $set: { avgPriceEuro: { $trunc: [ {$multiply: [$avgPrice], 0.86}, 2 ] } } ]
Cuando trabajas con agregaciones en MongoDB, dar formato al resultado final es tan importante como obtener los datos correctos. El operador $set ofrece una alternativa poderosa al operador $project, y saber cuándo usar cada uno puede optimizar significativamente tu flujo de trabajo al construir pipelines de agregación.
¿Cuál es la diferencia entre set y project en MongoDB?
La distinción principal es sencilla pero crucial: mientras $project excluye automáticamente todos los campos que no declares de forma explícita, $set incluye por defecto todos los campos que ya existían en la etapa anterior del pipeline [01:00]. Esto significa que con $set no necesitas listar cada campo que deseas conservar.
¿Cómo se usa el operador set para formatear reportes?
Partiendo de un pipeline que ya tiene datos agrupados con $group (donde se almacenaron propiedades como cantidad, precio media, más baja y más alta), el operador $set permite reorganizar esos datos sin perder ningún campo previo [02:24].
¿Cómo crear campos con nombres amigables?
Para generar un reporte legible, se pueden crear campos nuevos que hagan referencia a los datos existentes. Por ejemplo, un campo llamado "tipo de propiedad" puede apuntar al _id del grupo, y "cantidad de propiedades" puede referenciar al campo donde se almacenó la suma [03:20].
El operador $round resulta esencial para el formato numérico. Cuando los precios promedio vienen con demasiados decimales, este operador recibe un array con dos elementos: el campo numérico a formatear y la cantidad de decimales deseados [04:50]. Por ejemplo, aplicar $round con valor 2 al precio promedio entrega un resultado visualmente limpio con solo dos decimales.
¿Cómo crear objetos y arrays nuevos dentro de set?
Una de las capacidades más útiles de $set es la creación de estructuras que no existían previamente. En el ejemplo práctico, se construye un campo llamado "propiedades destacadas" que es un array con dos objetos [05:40]:
$más_baja.name y $más_baja.price.$más_alta.name y $más_alta.price.Esta técnica permite agrupar datos relacionados dentro de una estructura nueva y organizada, algo especialmente valioso cuando se generan reportes con información anidada.
¿Cómo combinar set con project para limpiar el resultado?
Un efecto secundario de $set es que los campos originales permanecen visibles junto con los campos nuevos, generando duplicidad en el resultado [07:30]. La solución es agregar una etapa adicional con $project al final del pipeline, donde se excluyen los campos no deseados asignándoles el valor cero:
_id: 0 para ocultar el identificador.precio_media: 0 porque ya existe como "precio promedio".cantidad: 0 porque ya se muestra como "cantidad de propiedades".más_baja: 0 y más_alta: 0 porque ya están dentro de "propiedades destacadas".De esta forma, el resultado final muestra únicamente los campos formateados: tipo de propiedad, cantidad de propiedades, precio promedio redondeado y propiedades destacadas como un array limpio con los dos objetos.
Combinar ambos operadores en un mismo pipeline es una práctica recomendada que aprovecha lo mejor de cada uno: $set para construir y computar, $project para excluir y depurar.
Como ejercicio práctico, intenta agregar un campo nuevo que convierta el precio promedio de dólares a euros usando una operación aritmética dentro de $set. Comparte tus resultados en los comentarios.
use('sample_airbnb') db.listingsAndReviews.aggregate([ { $match: { "address.country_code": "US" } }, { $sort: { property_type: 1, price : 1 } }, { $group: { _id: "$property_type", count:{ $sum: 1 }, precioMedia: { $avg: "$price" }, masBajo: { $first: { nombre: "$name", precio: "$price", direccion: "$address" } }, masAlto: { $last: { nombre: "$name", precio: "$price", direccion: "$address" } }, } }, { $set:{ "Tipo de Propiedad": "$_id", "Total": "$count", "Promedio": { $round: ["$precioMedia", 0] }, "Precio mas Bajo": { $round: ["$masBajo.precio", 0] }, "Precio mas Alto": { $round: ["$masAlto.precio", 0] }, " Propiedades destacadas": [ { "Tipo": "Mas bajo", "Nombre": "$masBajo.nombre", "Precio": "$masBajo.precio" }, { "Tipo": "Mas Alto", "Nombre": "$masAlto.nombre", "Precio": "$masAlto.precio" } ] } }, { $project: { _id: 0, precioMedia: 0, count: 0, masBajo: 0, masAlto: 0 } } ])
Solución del reto:
//media del precio, y que muestre el total por cada propiedad [ { $match: { "address.country_code": "US", }, }, { $sort: { property_type: 1, price: 1, }, }, // group by $property_type { $group: { _id: "$property_type", count:{ $sum: 1 }, priceAvgMedia:{ $avg: "$price" }, cheaper: { $first: { nombre: "$name", precio: "$price", direccion: "$address", }, }, moreExpensive: { $last: { nombre: "$name", precio: "$price", direccion: "$address", }, }, }, { $set:{ "Tipo de propiedad": "$_id", "Cantidad por propiedad": "$count", "Precio promedio por propiedad": {$round:["$priceAvgMedia",2]}, "propiedades destacadas":[ { "tipo":"cheaper", "nombre":"$cheaper.nombre", "precioDolar":"$cheaper.precio", "tipoCambio": 4.00, "precioEuro": {$multiply: ["$cheaper.precio", 4.0]} }, { "tipo":"moreExpensive", "nombre":"$moreExpensive.nombre", "precio":"$moreExpensive.precio", "tipoCambio": 4.00, "precioEuro": {$multiply: ["$moreExpensive.precio", 4.0]} } ] } }, { $project:{ _id:0, priceAvgMedia:0, count:0, cheaper:0, moreExpensive:0 } } ]
Carlos Orejuela
Para expresar el precio de dólares a euros y truncando el resultado a 2 decimales:
[ $set: { avgPriceEuro: { $trunc: [ {$multiply: [$avgPrice], 0.86}, 2 ] } } ]
Ronaldo Jiménez
Piero Nolte
Resolución de tarea con intervalos de precio en dólares y euros:```js use('sample_airbnb')
db.listingsAndReviews.aggregate( { $match: { "address.country": "United States" } }, { $sort: { property_type: 1, price: 1, }, }, { $addFields: { exchangeRate: 0.9253 } }, { $group: { _id: "$property_type", countProperties: { $sum: 1 }, avgPriceDolar: { $avg: "$price" }, avgPriceEuro: { $avg: { $multiply: ["$price", "$exchangeRate"] } }, mostExpensive: { $last: { name: "$name", priceDolar: "$price", priceEuro: { $multiply: ["$price", "$exchangeRate"] }, address: "$address" } }, cheapest: { $first: { name: "$name", priceDolar: "$price", priceEuro: { $multiply: ["$price", "$exchangeRate"] }, address: "$address" } } } }, { $set: { "Tipo de Propiedad": "$_id", "Opciones Disponibles": "$countProperties", "Precios en dolares": { "Precio más barato": "$cheapest.priceDolar", "Precio más elevado": "$mostExpensive.priceDolar", "Precio Promedio": { $round: ["$avgPriceDolar", 2] }, }, "Precios en Euros": { "Precio más barato": { $round: ["$cheapest.priceEuro", 2] }, "Precio más elevado": { $round: ["$mostExpensive.priceEuro", 2] }, "Precio Promedio": { $round: ["$avgPriceEuro", 2] }, }
} }, { $project: { "_id": 0, "exchangeRate": 0, "countProperties": 0, "avgPriceDolar": 0, "avgPriceEuro": 0, "cheapest": 0, "mostExpensive": 0 } }, { $limit: 10 }
)
Waldir Zapata Garcia
Excelente!.
Uso de $project y $set: $project:
$set:
Mi solución:
// $set sirve para crear campos nuevos en los documentos de salida. // Se utiliza para agregar nuevos campos a los documentos de entrada o para actualizar los valores de los campos existentes. use("sample_airbnb") db.listingsAndReviews.aggregate([ { $match: {"address.country_code": "US"}, }, { $sort:{ "property_type": 1, "price": 1}, }, { $group: { _id: "$property_type", contarPropiedades: { $sum: 1 }, precioPromedio: { $avg: "$price" }, "masBajo": { $first: { "nombre": "$name", "precio": "$price" } }, "masAlto":{ $last: { // ultimo elemento (mas caro) "nombre": "$name", "precio": "$price" } } } }, { $set:{ "Tipo de propiedad": "$_id", "Cantidad de propiedades": "$contarPropiedades", "Precio promedio": {$round:["$precioPromedio", 2]}, "propiedades destacadas":[ { "tipo":"Mas barata", "nombre":"$masBajo.nombre", "precioDolar":"$masBajo.precio", "precioEuro": {$round:[{$multiply: ["$masBajo.precio", 0.92]},2]} }, { "tipo":"Mas costosa", "nombre":"$masAlto.nombre", "precio":"$masAlto.precio", "precioEuro": {$round:[{$multiply: ["$masAlto.precio", 0.92]},2]} } ] } }, { // excluir campos para evitar duplicados $project: { "_id": 0, "contarPropiedades": 0, "precioPromedio": 0, "masBajo": 0, "masAlto": 0 } } ])