¿Cómo administro las conexiones MongoDB en una aplicación web Node.js?

Estoy usando el controlador node-mongodb-native con MongoDB para escribir un sitio web.

Tengo algunas preguntas sobre cómo administrar las conexiones:

  1. ¿Es suficiente usar solo una conexión MongoDB para todas las solicitudes? ¿Hay algún problema de rendimiento? Si no, ¿puedo configurar una conexión global para usar en toda la aplicación?

  2. De lo contrario, ¿es bueno si abro una nueva conexión cuando llega la solicitud y la cierro cuando gestioné la solicitud? ¿Es costoso abrir y cerrar una conexión?

  3. ¿Debería usar un grupo de conexión global? Escuché que el controlador tiene un grupo de conexión nativo. ¿Es una buena elección?

  4. Si utilizo un grupo de conexiones, ¿cuántas conexiones debería usar?

  5. ¿Hay otras cosas que debería notar?

El principal responsable del nodo-mongodb-native dice :

Abre MongoClient.connect una vez cuando su aplicación arranca y reutiliza el objeto db. No es un conjunto de conexiones singleton .connect crea un nuevo grupo de conexiones.

Entonces, para responder su pregunta directamente, reutilice el objeto db que resulta de MongoClient.connect (). Esto le proporciona agrupación y proporcionará un aumento de velocidad notable en comparación con las conexiones de apertura / cierre en cada acción de DB.

Abra una nueva conexión cuando se inicie la aplicación Node.js y reutilice el objeto de conexión db existente:

/server.js

 import express from 'express'; import Promise from 'bluebird'; import logger from 'winston'; import { MongoClient } from 'mongodb'; import config from './config'; import usersRestApi from './api/users'; const app = express(); app.use('/api/users', usersRestApi); app.get('/', (req, res) => { res.send('Hello World'); }); // Create a MongoDB connection pool and start the application // after the database connection is ready MongoClient.connect(config.database.url, { promiseLibrary: Promise }, (err, db) => { if (err) { logger.warn(`Failed to connect to the database. ${err.stack}`); } app.locals.db = db; app.listen(config.port, () => { logger.info(`Node.js app is listening at http://localhost:${config.port}`); }); }); 

/api/users.js

 import { Router } from 'express'; import { ObjectID } from 'mongodb'; const router = new Router(); router.get('/:id', async (req, res, next) => { try { const db = req.app.locals.db; const id = new ObjectID(req.params.id); const user = await db.collection('user').findOne({ _id: id }, { email: 1, firstName: 1, lastName: 1 }); if (user) { user.id = req.params.id; res.send(user); } else { res.sendStatus(404); } } catch (err) { next(err); } }); export default router; 

Fuente: Cómo abrir conexiones de bases de datos en una aplicación Node.js / Express

Aquí hay un código que administrará sus conexiones de MongoDB.

 var MongoClient = require('mongodb').MongoClient; var url = require("../config.json")["MongoDBURL"] var option = { db:{ numberOfRetries : 5 }, server: { auto_reconnect: true, poolSize : 40, socketOptions: { connectTimeoutMS: 500 } }, replSet: {}, mongos: {} }; function MongoPool(){} var p_db; function initPool(cb){ MongoClient.connect(url, option, function(err, db) { if (err) throw err; p_db = db; if(cb && typeof(cb) == 'function') cb(p_db); }); return MongoPool; } MongoPool.initPool = initPool; function getInstance(cb){ if(!p_db){ initPool(cb) } else{ if(cb && typeof(cb) == 'function') cb(p_db); } } MongoPool.getInstance = getInstance; module.exports = MongoPool; 

Cuando inicie el servidor, llame a initPool

 require("mongo-pool").initPool(); 

Luego, en cualquier otro módulo, puede hacer lo siguiente:

 var MongoPool = require("mongo-pool"); MongoPool.getInstance(function (db){ // Query your MongoDB database. }); 

Esto se basa en la documentación de MongoDB . Mira esto.

Si tiene Express.js, puede usar express-mongo-db para almacenar en caché y compartir la conexión MongoDB entre solicitudes sin un grupo (ya que la respuesta aceptada dice que es la forma correcta de compartir la conexión).

De lo contrario, puede ver su código fuente y usarlo en otro marco.

Administre los pools de conexión mongo en un solo módulo autónomo. Este enfoque proporciona dos beneficios. Primero, mantiene su código modular y más fácil de probar. En segundo lugar, no está obligado a mezclar su conexión de base de datos en su objeto de solicitud que NO es el lugar para un objeto de conexión de base de datos. (Dada la naturaleza de JavaScript, consideraría altamente peligroso mezclar algo con un objeto construido por código de biblioteca). Entonces con eso solo necesitas considerar un módulo que exporta dos métodos. connect = () => Promise y get = () => dbConnectionObject .

Con dicho módulo, primero puede conectarse a la base de datos

 // runs in boot.js or what ever file your application starts with const db = require('./myAwesomeDbModule'); db.connect() .then(() => console.log('database connected')) .then(() => bootMyApplication()) .catch((e) => { console.error(e); // Always hard exit on a database connection error process.exit(1); }); 

Cuando está en vuelo, su aplicación simplemente puede llamar a get() cuando necesita una conexión de base de datos.

 const db = require('./myAwesomeDbModule'); db.get().find(...)... // I have excluded code here to keep the example simple 

Si configura su módulo db de la misma manera que lo siguiente, no solo tendrá una manera de asegurarse de que su aplicación no arrancará a menos que tenga una conexión de base de datos, sino que también tendrá acceso global a su grupo de conexiones de base de datos que generará un error si no tienes una conexión

 // myAwesomeDbModule.js let connection = null; module.exports.connect = () => new Promise((resolve, reject) => { MongoClient.connect(url, option, function(err, db) { if (err) { reject(err); return; }; resolve(db); connection = db; }); }); module.exports.get = () => { if(!connection) { throw new Error('Call connect first!'); } return connection; } 

He estado usando generic-pool con conexiones redis en mi aplicación, lo recomiendo encarecidamente. Es genérico y definitivamente sé que funciona con mysql, así que no creo que tenga ningún problema con él y mongo

https://github.com/coopernurse/node-pool

http://mongoosejs.com/docs/api.html

Mira la fuente de Mongoose. Abren una conexión y la vinculan a un objeto Model, por lo que cuando se requiere el Objeto modelo, se establece una conexión con el DB. El controlador se encarga de la agrupación de conexiones.

Debe crear una conexión como servicio y luego volver a utilizarla cuando lo necesite.

 // db.service.js import { MongoClient } from "mongodb"; import database from "../config/database"; const dbService = { db: undefined, connect: callback => { MongoClient.connect(database.uri, function(err, data) { if (err) { MongoClient.close(); callback(err); } dbService.db = data; console.log("Connected to database"); callback(null); }); } }; export default dbService; 

mi muestra de App.js

 // App Start dbService.connect(err => { if (err) { console.log("Error: ", err); process.exit(1); } server.listen(config.port, () => { console.log(`Api runnning at ${config.port}`); }); }); 

y úsalo donde quieras

 import dbService from "db.service.js" const db = dbService.db 

He implementado el código a continuación en mi proyecto para implementar la agrupación de conexiones en mi código, por lo que creará una conexión mínima en mi proyecto y reutilizará la conexión disponible.

 /* Mongo.js*/ var MongoClient = require('mongodb').MongoClient; var url = "mongodb://localhost:27017/yourdatabasename"; var assert = require('assert'); var connection=[]; // Create the database connection establishConnection = function(callback){ MongoClient.connect(url, { poolSize: 10 },function(err, db) { assert.equal(null, err); connection = db if(typeof callback === 'function' && callback()) callback(connection) } ) } function getconnection(){ return connection } module.exports = { establishConnection:establishConnection, getconnection:getconnection } /*app.js*/ // establish one connection with all other routes will use. var db = require('./routes/mongo') db.establishConnection(); //you can also call with callback if you wanna create any collection at starting /* db.establishConnection(function(conn){ conn.createCollection("collectionName", function(err, res) { if (err) throw err; console.log("Collection created!"); }); }; */ // anyother route.js var db = require('./mongo') router.get('/', function(req, res, next) { var connection = db.getconnection() res.send("Hello"); }); 

El mejor enfoque para implementar la agrupación de conexiones es crear una variable de matriz global que contenga el nombre de db con el objeto de conexión devuelto por MongoClient y luego reutilizar esa conexión cada vez que necesite ponerse en contacto con la base de datos.

  1. En su Server.js, defina var global.dbconnections = [];

  2. Crea un servicio que nombra connectionService.js. Tendrá 2 métodos getConnection y createConnection. Entonces, cuando el usuario llame a getConnection (), encontrará detalles en la variable de conexión global y devolverá los detalles de la conexión si ya existe, llamará a createConnection () y devolverá los detalles de la conexión.

  3. Llame a este servicio utilizando db_name y devolverá el objeto de conexión si ya lo tiene, creará una nueva conexión y se lo devolverá.

Espero eso ayude 🙂

Aquí está el código connectionService.js:

 var mongo = require('mongoskin'); var mongodb = require('mongodb'); var Q = require('q'); var service = {}; service.getConnection = getConnection ; module.exports = service; function getConnection(appDB){ var deferred = Q.defer(); var connectionDetails=global.dbconnections.find(item=>item.appDB==appDB) if(connectionDetails){deferred.resolve(connectionDetails.connection); }else{createConnection(appDB).then(function(connectionDetails){ deferred.resolve(connectionDetails);}) } return deferred.promise; } function createConnection(appDB){ var deferred = Q.defer(); mongodb.MongoClient.connect(connectionServer + appDB, (err,database)=> { if(err) deferred.reject(err.name + ': ' + err.message); global.dbconnections.push({appDB: appDB, connection: database}); deferred.resolve(database); }) return deferred.promise; }