¿Cómo almacenar resultados de consultas en MongoDB?
En muchas ocasiones, al trabajar con una base de datos en MongoDB, es crucial no solo realizar consultas complejas, sino también almacenar los resultados para su reutilización y acceso rápido. Pero, ¿cómo se puede lograr esto de manera efectiva? La respuesta reside en el uso del operador out, el cual permite generar una nueva colección en tu base de datos con los resultados de un pipeline de agregación. Este enfoque es especialmente útil para exportaciones, reportes, y como caché para consultas frecuentes.
¿Qué es el operador out y para qué se utiliza?
El operador out es una herramienta poderosa que te permite:
Crear copias de tus consultas en formato de colección nueva. Ideal para facilitar la exportación de datos.
Guardar resultados complejos para acceso rápido y reutilización por otros departamentos o procesos.
Preservar consultas como caché que pueden luego usarse en reportes sin necesidad de repetir el procesamiento de datos.
¿Cómo se implementa el operador out en MongoDB Compass?
Un ejemplo práctico de uso del operador out es cuando deseas conocer los barrios más costosos de una ciudad a partir de los datos de propiedades. El proceso en MongoDB Compass implicaría los siguientes pasos:
Ordenamiento de Datos: Comienza con una etapa sort para ordenar las propiedades por precio de manera descendente.
{ $sort:{"address.market":1,"precio":-1}}
Agrupación de Datos: Emplea una etapa group para agrupar las propiedades por barrio, obteniendo simplemente la propiedad más costosa de cada grupo:
Uso del operador out: Finalmente, utiliza el operador out para almacenar los resultados en una nueva colección llamada propiedades más costosas.
{ $out:"propiedades más costosas"}
Una vez ejecutado, aparecerá una nueva colección con estos resultados en tu base de datos.
Recomendaciones y consideraciones al usar el operador out
El operador out debe ser empleado cuidadosamente en cualquier pipeline por las siguientes razones:
Debe ser la última etapa de tu pipeline. Es crucial que todo el procesamiento ocurra antes de empujar los resultados a la nueva colección.
Sobrescribe sin confirmar: Si la colección con el mismo nombre ya existe, esta será automáticamente reemplazada.
Impacto en rendimiento: Crear nuevas colecciones cada vez que ejecutas un pipeline podría afectar la eficiencia de la base de datos.
Pérdida de índices: Si la colección original tenía índices, estos no se transfieren automáticamente a la nueva colección generada.
La práctica con el operador out es esencial, en especial en escenarios donde se necesita proveer datos preprocesados a otros departamentos que no trabajan directamente con MongoDB. Con el uso adecuado, puedes crear pipelines eficientes que beneficien a tu organización en general. ¡Sigue explorando y compartiendo tus hallazgos para continuar aprendiendo y mejorando en el manejo de bases de datos con MongoDB!
use('sample_airbnb')db.listingsAndReviews.aggregate([{$sort:{"address.market":1,price:-1}},{$group:{_id:"$address.market",masCostosas:{$first:{nombre:"$name",precio:"$price"}}}},// con esto guardamos esto como una colección{$out:"Propiedades_Mas_Costosas"}])db.Propiedades_Mas_Costosas.find()
Código visto en clase
db.orders.updateOne(// actualizamos la orden{// hacemos match con la orden que queremos actualizar_id:ObjectId('649cb8c89f973670e36e123f')},{// mostramos el cambio, agregando un nuevo elemento$push:{// agregar elementoitems:{// quien se lo agregoname:'Producto 1',qty:2,price:12,product_id:ObjectId('649923f457514437ac501dd4')}},$inc:{// incrementadortotal:12*2// total = total + price * qty}})//[{$sort:{"address.market":1,price:-1}},{$group:{_id:"$address.market",masCostosas:{$first:{name:"$name",price:"$price"}}}},{$out:"propiedadesMasCostosas"}]
Propuesta del reto:
// Datos de una propiedad en formato tarjeta[{$project:{_id:0,name:1,description:1,random_discount:{$min:[0.2,{$rand:{}}]},beds:{$concat:[{$toString:"$beds"}," camas"]},price:1,f_inicio:{$dateToString:{date:"$$NOW",format:"%d/%m"}},f_fin:{$dateAdd:{startDate:"$$NOW",unit:"day",amount:{$toInt:"$minimum_nights"}}},picture:"$images.picture_url",number_of_reviews:{$size:"$reviews"},rating:"$review_scores.review_scores_rating"}},{$project:{name:1,description:1,beds:1,price:1,picture:1,rating:1,number_of_reviews:1,duracion:{$concat:["$f_inicio","-",{$dateToString:{date:"$f_fin",format:"%d/%m"}}]},price_discount:{$trunc:[{$multiply:["$price",{$subtract:[1,"$random_discount"]}]},2]},rating:{$multiply:[5/100,"$rating"]}// Escala del 1 al 5}},{$project:{picture:1,name:1,description:1,beds:1,duracion:1,rating:{$concat:[{$toString:"$rating"}," (",{$toString:"$number_of_reviews"},")"]},price:{$concat:[{$toString:"$price"}," -> ",{$toString:"$price_discount"}," USD noche"]}}}]
Ejemplo de documento:
{"name":"Ribeira Charming Duplex","description":"Fantastic duplex apartment with three bedrooms, located in the historic area of Porto, Ribeira (Cube) - UNESCO World Heritage Site. Centenary building fully rehabilitated, without losing their original character. Privileged views of the Douro River and Ribeira square, our apartment offers the perfect conditions to discover the history and the charm of Porto. Apartment comfortable, charming, romantic and cozy in the heart of Ribeira. Within walking distance of all the most emblematic places of the city of Porto. The apartment is fully equipped to host 8 people, with cooker, oven, washing machine, dishwasher, microwave, coffee machine (Nespresso) and kettle. The apartment is located in a very typical area of the city that allows to cross with the most picturesque population of the city, welcoming, genuine and happy people that fills the streets with his outspoken speech and contagious with your sincere generosity, wrapped in a only parochial spirit. We are always available to help guests","beds":"5 camas","picture":"https://a0.muscache.com/im/pictures/e83e702f-ef49-40fb-8fa0-6512d7e26e9b.jpg?aki_policy=large","duracion":"02/11-04/11","rating":"4.45 (51)","price":"80.00 -> 75.70 USD noche"}
Comparto mi solución al reto:
Para generar los atributos Nombre de Propiedad, Tipo de propiedad, Imagen de Propiedad, Número de camas, los seleccioné de los atributos ya listos en la info general.
Para general el atributo del precio real, decidí sumar los atributos price, security_deposit, cleaning_fee de la info general.
Para general el atributo del precio con descuento, tomé el atributo del precio real y le resté el 30% (valor arbirtrario).
Para el atributo de calificación, decidí tomar el atributo review_scores.review_scores_rating y como está en una escala de 1-100, lo dividí entre 20, para que quedara en una escala de 1-5.
Para el atributo número de reviews, tomé el valor del atributo number_of_reviews de la info general.
Decidí agregarle el atributo de personas permitidas (no es solicitado pero me pareció interesante agregarlo en la tarjeta).
Para los valores de Mínima y Máxima Estancia, decidí calcular la fecha del día actual y sumarle los valores de minimum_nights y maximum_nights.
Para que el mes me quedará en formato de letras, tuve que hacer un array con los meses e indexarlo con el valor resultante del mes extraído de la fecha (esto porque tengo una versión de mongo inferior a la 7.0.0, si ya se cuenta con esta versión o una superior, solo será necesario agregarle el operador correspondiente al momento de formatear la fecha).
Dejo mi código en el siguiente comentario.
Aqui mi solucion al reto, aunque no es como me lo esperaba y no me quize complicar 😅.
En la base de datos no hay calificacion de 1-5⭐ asi que use el valor de review_scores_rating que es una puntacion de 1-100 y lo ordene de forma descendente en base al review_scores_rating.
Aqui el codigo 👇
use("sample_airbnb")db.listingsAndReviews.aggregate([{$sort:{"review_scores.review_scores_rating":-1}},{$project:{"_id":0,"Nombre de la propiedad:":"$name","Imagen de la propiedad:":"$images.picture_url","Tipo de propiedad:":"$property_type","Numero de camas:":"$beds","Noches minimas de estadia:":"$minimum_nights","Noches maximas de estadia:":"$maximum_nights","Precio:":"$price","Numero de reviews:":"$number_of_reviews","Rating total de las reviews":"$review_scores.review_scores_rating"}},{$limit:1000},{$out:"designersReport"}])