Cómo administro las conexiones MongoDB en un nodo.js aplicación web?


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

Tengo algunas preguntas sobre cómo administrar conexiones:

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

  2. Si no, ¿es bueno si abro una nueva conexión cuando llega la solicitud y la cierro cuando se maneja la solicitud? Es caro para abrir y cerrar una conexión?

  3. ¿Debo usar un grupo de conexiones global? He oído que el conductor tiene una piscina de conexión nativa. ¿Es una buena elección?

  4. Si uso un grupo de conexiones, ¿cuántas conexiones se deben usar?

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

Author: Peter Mortensen, 2012-05-18

10 answers

El committer principal a node-mongodb-native dice :

Abres do MongoClient.conéctese una vez cuando su aplicación se inicie y reutilice el objeto db. No es un grupo de conexiones individuales cada uno .conectar crea un nuevo grupo de conexiones.

Por lo tanto, para responder a su pregunta directamente, reutilice el objeto db que resulta de MongoClient.conectar(). Esto le da agrupación, y proporcionará un aumento de velocidad notable en comparación con las conexiones de apertura / cierre en cada db acto.

 381
Author: Max,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-22 17:41:07

Abra una nueva conexión cuando el nodo.se inicia la aplicación js y reutiliza 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 Base de datos en un nodo.js / Express App

 30
Author: Konstantin Tarkus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 18:26:58

Aquí hay un código que administrará sus conexiones 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 puedes 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. Échale un vistazo.

 14
Author: Yaki Klein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 18:28:49

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

Si no, puede mirar su código fuente y usarlo en otro marco.

 11
Author: floatdrop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-15 18:25:01

Administre los grupos de conexiones mongo en un único módulo autónomo. Este enfoque ofrece dos beneficios. En primer lugar, 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 cualquier cosa con un objeto construido por código de biblioteca). Así que con eso solo necesita considerar un módulo que exporta dos métodos. connect = () => Promise y get = () => dbConnectionObject.

Con un módulo de este tipo se puede conectar en primer lugar 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 de base de datos de la misma manera que lo siguiente, no solo tendrá una forma de asegurarse de que su aplicación no se arranque a menos que tenga una conexión de base de datos, también tendrá una forma global de acceder a su grupo de conexiones de base de datos que se producirá un error si no tiene una relació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;
}
 9
Author: Stewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-24 03:39:40

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 tengas ningún problema con él y mongo

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

 6
Author: ControlAltDel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-18 18:12:04

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

Echa un vistazo a la fuente de Mangosta. Abren una conexión y la vinculan a un objeto Modelo, de modo que cuando se requiere el objeto modelo, se realiza una conexión a la base de datos. El controlador se encarga de la agrupación de conexiones.

 3
Author: srquinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-18 21:26:34

Debe crear una conexión como servicio y luego reutilizarla cuando sea necesario.

// 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 Aplicación.js sample

// 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 con

import dbService from "db.service.js"
const db = dbService.db
 2
Author: LeeKaD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-26 20:43:09

He implementado el siguiente código en mi proyecto para implementar el pooling de conexiones en mi código para que cree una conexión mínima en mi proyecto y reutilice 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");

});
 1
Author: Aditya Parmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-22 08:18:49

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

  1. En su Servidor.js define var global.dbconnections = [];

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

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

Espero que ayude:)

Aquí está el connectionService.código 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;
} 
 1
Author: RRPatel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-17 06:58:03