Les dejo un tip. En las buenas prácticas de Mongo dice que debemos crear sóla una conexxión y esa reutilizarla cada vez que hagamos una llamada a la BDD. Les dejo como yo lo hice:
asyncconnect(){if(!MongoLib.connection){try{awaitthis.client.connect()console.log('Connected successfully to mongo')MongoLib.connection=this.client.db(this.dbName)}catch(error){console.log(error)}}returnMongoLib.connection}
Quiero expresar mi desconformidad con esta clase. ¿que se supone que tenga que apender de ella si todo lo que me muestra es al profesor enviando request en postman (que ya las tiene hechas de antemano), y una camara rapida desarrollando las funciones del CRUD? :/
Voy a intentar entender el codigo por mi cuenta, pero me quedo con un muy mal sabor de boca.
Hola Sebas,
Lamento escuchar eso. Este curso podría ayudarte a entender los fundamentos de MongoDB, como bien sugieres es un tema muy extenso y en una clase no podríamos abarcar el contenido. Pero estoy seguro que con ese curso podrían quedar más claros los fundamentos de un CRUD en mongodb.
¿En qué momento se cierra las conexiones a BD?
Por lo que entiendo, en cada operación que realiza se abre una nueva conexión pero nunca la cierra.
En teoría no se cierran debido a que estás construyendo un API el cual "siempre va a estar corriendo" del lado del servidor. Sin embargo, como lo comenta @Luis_LiraC, la mejor práctica es mantener una sola sesión con mongo de la siguiente manera:
asyncconnect(){if(!MongoLib.connection){try{ awaitthis.client.connect()console.log('Connected successfully to mongo')MongoLib.connection=this.client.db(this.dbName)}catch(error){console.log(error)}}returnMongoLib.connection}
A alguien le salta un warning de mongodb al hacer dos conexiones simultaneas?
Este es el warning:
the options [servers] is not supported
the options [caseTranslate] is not supported
the options [username] is not supported
the server/replset/mongos/db options are deprecated, all their options are supported at the top level of the options object [poolSize,ssl,sslValidate,sslCA,sslCert,sslKey,sslPass,sslCRL,autoReconnect,noDelay,keepAlive,keepAliveInitialDelay,connectTimeoutMS,family,socketTimeoutMS,reconnectTries,reconnectInterval,ha,haInterval,replicaSet,secondaryAcceptableLatencyMS,acceptableLatencyMS,connectWithNoPrimary,authSource,w,wtimeout,j,forceServerObjectId,serializeFunctions,ignoreUndefined,raw,bufferMaxEntries,readPreference,pkFactory,promiseLibrary,readConcern,maxStalenessSeconds,loggerLevel,logger,promoteValues,promoteBuffers,promoteLongs,domainsEnabled,checkServerIdentity,validateOptions,appname,auth,user,password,authMechanism,compression,fsync,readPreferenceTags,numberOfRetries,auto_reconnect,minSize,monitorCommands,retryWrites,useNewUrlParser]
X2
a mi me pasa lo mismo
estuve viendo que cada vez que se hacia una acción CRUD se conectaba con el cliente de mongoDB, por lo que he leído no es recomendable conectarse tantas veces, sino hacer 1 sola conexión y mantener 1 instancia activa de mongoDB mientras el usuario esté activo, asi que por lo que ví en el curso de esenciales de nodejs en la cual el profesor Emir Salazar recomendaba 1 sola instancia, le hice modificaciones a el archivo donde nos conectamos a mongo, ahora solo se conecta 1 vez con mongo cuando arranca el index.js de la app y se mantiene la instancia. quedando asi el archivo mongo.js:
// carlos eduardo// @carlosEdua -> github// @cems -> platzi // standart class to connect, use and disconnect mongoDB with// one instance const{MongoClient}=require("mongodb");const{ dbName, dbUSer, dbPassword
}=require("../config/config");constURI=`mongodb+srv://${dbUSer}:${dbPassword}@${dbName}-ydbgb.mongodb.net/test?retryWrites=true&w=majority`;// ***** global instance of mongo *****letINSTANCE=null;// **************************************classMongoLib{constructor(){// crear un cliente de mongoDB, mas no conectarse aúnthis.client=newMongoClient(URI,{useNewUrlParser:true});this.dbName= dbName;this.instance=INSTANCE;this.db=INSTANCE?INSTANCE.db(dbName):null;}asyncconnect(){try{// conectarse al clienteconst clientConnected =awaitthis.client.connect();// referenciar instanciathis.instance= clientConnected;INSTANCE= clientConnected;// obtener la base de datos// this.db = await this.instance.db(this.dbName);console.log("base de datos conectada!!!");// return true for run the appreturntrue;}catch(err){returnnewError(err)}}asyncdisconnect(){try{if(this.instance)awaitthis.instance.close();}catch(err){returnError(err)}}// =================== CRUD ====================// ## create ##createOne(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).insertOne(query);}createMany(collection, arr){const{instance, dbName}=this;return instance.db(dbName).collection(collection).insertMany(arr);}// ## find ##getAll(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).find(query).toArray();}getOne(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).findOne(query);}// ## update ##updateOne(collection, query, newValue){const{instance, dbName}=this;return instance.db(dbName).collection(collection).updateOne(query, newValue);}updateMany(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).updateMany(query);}// ## delete ##deleteOne(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).deleteOne(query);}deleteMany(collection, query){const{instance, dbName}=this;return instance.db(dbName).collection(collection).deleteMany(query);}// ## drop ##dropCollection(collection){const{instance, dbName}=this;return instance.db(dbName).collection(collection).drop();}}module.exports=MongoLib;
en la carpeta services el archivo products.js quedaría asi:
// script para comunicarse con las librerías de BDD y mandarselo// al controlador// aqui se controla la logica de negocio para los productos// tal como: crear, pedir, actualizar y borrarconstMongoLib=require("../mongo/mongo");const{ObjectID}=require("mongodb");classproductService{constructor(collection){this.mongo=newMongoLib();this.collection= collection;}// ================== get products ==================asyncgetProducts({tags, productName}){// ver si se busca por tags o productName y en caso de no tener// asignar un objeto vacioconst byTags = tags ?{tags:{ $in:JSON.parse(tags)}}:null;const byName = productName ?{productName:newRegExp(productName)}:null;const query =(byTags || byName)||{};const products =awaitthis.mongo.getAll(this.collection, query);return products;}asyncgetProduct(id){constID=newObjectID(id);const product =awaitthis.mongo.getOne(this.collection,{_id:ID});return product;}// ==================== create products ===================asynccreateProduct({ body }){const productCreated =awaitthis.mongo.createOne(this.collection, body);return productCreated;}// ==================== update products ===================asyncupdateOneProduct(id, newValues){constID=newObjectID(id);// por si se actualiza más de 1 campolet newValuesObject ={};for(let key in newValues){ newValuesObject[key]= newValues[key];}const productUpdated =awaitthis.mongo.updateOne(this.collection,{_id:ID},{$set: newValuesObject});return productUpdated;}// ================= remove products ==================asyncremoveProduct(id){constID=newObjectID(id);const productDeleted =awaitthis.mongo.deleteOne(this.collection,{_id:ID});return productDeleted;}}module.exports= productService;
y las rutas de la API la tengo asi:
const router =require("express").Router();constProductServices=require("../../services/products");// get all productsrouter.get("/",async(req, res, next)=>{// nueva instancia de los servicios para comunicarse// con la instancia ya creada de mongoDBconst productServices =newProductServices("products");const{ tags, productName }= req.query;try{const products =await productServices.getProducts({tags, productName}); res.send(products);}catch(err){next(err);}})// get one productrouter.get("/:productId",async(req, res, next)=>{const{ productId }= req.params;const productServices =newProductServices("products");try{const products =await productServices.getProduct(productId); res.send(products);}catch(err){next(err);}})// create a productrouter.post("/",async(req, res, next)=>{const productServices =newProductServices("products");const product = req.body;try{const productCreated =await productServices.createProduct({body: product}); res.send(productCreated);}catch(err){next(err);}})// update a productrouter.put("/:productId",async(req, res, next)=>{const productServices =newProductServices("products");const newProductValues = req.body;const{ productId }= req.params;try{const productUpdated =await productServices.updateOneProduct(productId, newProductValues); res.send(productUpdated);}catch(err){next(err);}})// delete a productrouter.delete("/:productId",async(req, res, next)=>{const productServices =newProductServices("products");const{ productId }= req.params;try{const productErased =await productServices.removeProduct(productId); res.send(productErased);}catch(err){next(err);}})module.exports= router;
por ultimo el index.js queda de la siguiente manera:
const express =require("express");const hbs =require("express-handlebars");const viewRoutes =require("./routes/views/products");const apiRoutes =require("./routes/api/productsApi");const path =require("path");constMongoLib=require("./mongo/mongo");// appconst app =express();const mongo =newMongoLib();// middlewaresapp.use(express.json());// set view engineapp.engine('hbs',hbs({extname:'hbs',defaultLayout:"index.hbs",layoutsDir: path.join(__dirname,'views/'),partialsDir:[// path to your partials path.join(__dirname,'views/partials'),]}));app.set("views","./views");app.set("view engine","hbs");// routesapp.use("/products", viewRoutes);app.use("/api/products", apiRoutes);// redirectapp.use("/",(req,res)=>{ res.redirect("/products");})// run the serverfunctionrun(){ app.listen( process.env.PORT||4500,()=>{console.log("server created");})}// iniciar conexión con mongoDB e iniciar servidor si// la conexión fué exitosa mongo.connect().then(()=>{run();// desconectar mongoDB si se cierra el programa process.on("SIGINT", mongo.disconnect); process.on("SIGTERM", mongo.disconnect);}).catch(err=>console.log("DB not connected ", err));
creo que es una mejor implementación pero eso ya depende del proyecto y de cada quien.
Me marca que this.instance es null, ¿sabrás por qué?
Por qué este y los anteriores cursos de mongoDB, al momento de crear un CRUD lo hacen de una forma irreal y nada útil para productivo ni para un cliente? Creo que están decayendo la calidad de los cursos en Platzi, preferiría tener menos al año pero que los hagan completos y apegados a la realidad y que actualicen los que están obsoletos.
Este curso es de Express.js lo que se ve de MongoDB es una introducción para saber como manejarlo a travez del framework.
Si puedes ser mas especifico respecto a porque consideras que esta creado de una manera irreal, con gusto te ayudo a responder tus dudas.
Interesante y cual seria la formas más real y más útil de usar grub con Mongodb alguna tutorial.
Me parece de mal gusto estar enseñando a hacer un CRUD en Express de Mongo y ponerlo en cámara rápida, hay personas, como yo, que estamos aprendiendo también a trabajar con Mongo y si el curso de Mongo no es prerequisito para tomar este curso no entiendo por qué le adelantan, entonces no deberían poner el ejercicio. Muy mal hecho.
Ary, siento mucho que este paso en cámara rápida no haya ayudado a tu aprendizaje.
El Curso Básico de MongoDB no es prerrequisito porque, efectivamente, no es necesario entender MongoDB al 100% para empezar a trabajar con Express.js. Pero es 99% seguro que eventualmente vamos a terminar trabajando com ambos.
Además de esto (y de que puedes tomar el curso de mongo), ¿hay algo en lo que podamos ayudarte?
Hola juandc, si, como mencioné en otro video hay que actualizar este curso, la conexión a mongo ya no se hace como se expone en el video y si deberían considerar colocar el video completo (sin la cámara rápida), entiendo que está el recurso en el repositorio pero eso al menos a mí me hace perder el hilo de la clase y vengo a la clase a aprender cómo se hace del maestro, no a copiar y pegar código, si fuera eso solo clonaría el repositorio sin necesidad de ver el curso y no se trata de eso.
Cual es tu opinion acerca de mongoose? ¿Porque no lo usas en tu proyecto?
Mongoose como ODM (Object Document Mapper) es muy completo y eficiente. Sin embargo, al igual que pasa con los ORM (Object Relational Mapper) en las bases de datos relacionales, saber un ODM/ORM nos sesga un poco de como funciona la base de datos realmente. Mi recomendación es siempre tratar de aprender las bases. Esta bien usar un ODM/ORM para empezar pero a medida que quieres volverte mas experto ve a las bases, ya que asi podras aprovechar las librerias/herramientas mejor.
Tenemos un problema con la re-conexión a la base de datos.
sucede que cuando se corta el internet, lanza un error del que jamás se puede volver a recuperar.
si a alguien le sale que ObjectId is not defined, recuerden de extraelo de mongodb
const{MongoClient,ObjectId}=require('mongodb')
en la linea 57:
.updateOne({_id:ObjectId(id)},{$set: data },{upsert:true})
al colocar upsert:true, no se supondría que mongo crearía un nuevo documento (con la data enviada) en caso de no encontrar el documento con ese _id respectivo? esto estaria bien implementado? ya que se supone que el metodo update es solo para actualizar y no para crear
En la documentación oficial https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/ explica como funciona, si no encuentra un documento que cumpla con el filter lo va a crear y si lo encuentra lo actualiza, por defecto es false por lo tanto siempre va a intentar actualizar y si no hay algo que coincida con el filtro va a fallar.
Muy buena apreciación, de hecho cuando desde postman elimina el registro del 'butaco blanco' y lo vuelve a crear y lo actualiza, como no cambió el productId en el environment por el nuevo id del 'butaco blanco', entonces se crea un nuevo documento para 'black bike'.
¿Por qué no me sale la vista de productos en la web, si todo está correcto (obviamente no...)?
Conexión a mongoDB correcta, funciones iguales a las del profe... He intentado colocar 3 productos en la base de datos, en la collection que llamamos 'products' y nada, no me las enseña en la web...
¿Alguna sugerencia?
¿Tienes el link del repositorio del proyecto?
Eso es porque tienes que cambiar la función que viene en el archivo de views a async/await, a mí me pasó igual, mira:
Empieza a debuggear usando console.log() , ve a los servicios y checa el metodo createProduct mira si al haces el await de this.mongoDB.create te devuelve algo ... si no checa que este bien la la creacion de un dato con mongodb en mongo.js