web-dev-qa-db-fra.com

Comment gérer les connexions MongoDB dans une application Web Node.js?

J'utilise le pilote node-mongodb-native avec MongoDB pour écrire un site Web.

J'ai quelques questions sur la gestion des connexions:

  1. Est-il suffisant d'utiliser une seule connexion MongoDB pour toutes les demandes? Existe-t-il des problèmes de performances? Si non, puis-je configurer une connexion globale à utiliser dans toute l'application?

  2. Si ce n'est pas le cas, est-ce bon d'ouvrir une nouvelle connexion lorsque la demande arrive et de la fermer lorsque la demande est traitée? Est-ce coûteux d'ouvrir et de fermer une connexion?

  3. Devrais-je utiliser un pool de connexion global? J'entends le pilote a un pool de connexion natif. est-ce un bon choix?

  4. Si j'utilise un pool de connexions, combien de connexions doivent être utilisées?

  5. Y a-t-il autre chose que je devrais remarquer?

247
Freewind

Le committer principal de node-mongodb-native dit :

Vous ouvrez do MongoClient.connect une fois lorsque votre application démarre et réutilisez l'objet db. Ce n'est pas un pool de connexions singleton. Chaque .connect crée un nouveau pool de connexions.

Donc, pour répondre directement à votre question, réutilisez l'objet db résultant de MongoClient.connect (). Cela vous donne la mise en commun, et fournira une augmentation de vitesse notable par rapport aux connexions d'ouverture/fermeture sur chaque action de la base de données.

424
Max

Ouvrez une nouvelle connexion lorsque l'application Node.js démarre et réutilisez l'objet de connexion db existant:

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

Source: Comment ouvrir des connexions de base de données dans un Node.js/Express App

39
Konstantin Tarkus

Voici un code qui gérera vos connexions 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;

Lorsque vous démarrez le serveur, appelez initPool

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

Ensuite, dans tout autre module, vous pouvez effectuer les opérations suivantes:

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

Ceci est basé sur documentation MongoDB . Jetez un coup d'oeil.

16
Yaki Klein

Gérez les pools de connexions Mongo dans un seul module autonome. Cette approche offre deux avantages. Premièrement, votre code reste modulaire et facile à tester. Deuxièmement, vous n'êtes pas obligé de mélanger votre connexion à la base de données dans votre objet de requête, ce qui n'est PAS l'emplacement d'un objet de connexion à une base de données. (Compte tenu de la nature de JavaScript, j’estime qu’il est très dangereux de mélanger quoi que ce soit avec un objet construit avec le code de bibliothèque). Donc, avec cela, il suffit de considérer un module qui exporte deux méthodes. connect = () => Promise et get = () => dbConnectionObject.

Avec un tel module, vous pouvez d’abord vous connecter à la base de données

// 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);
    });

En vol, votre application peut simplement appeler get() lorsqu'elle a besoin d'une connexion à une base de données.

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

Si vous configurez votre module de base de données de la même manière que ce qui suit, vous aurez non seulement le moyen de vous assurer que votre application ne démarrera pas à moins que vous n'ayez une connexion à une base de données, vous disposez également d'un moyen global d'accéder à votre pool de connexions à la base de données, ce qui entraînera une erreur si vous n'avez pas de connexion.

// 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;
}
11
Stewart

Si vous avez Express.js, vous pouvez utiliser express-mongo-db pour mettre en cache et partager la connexion MongoDB entre des requêtes sans pool (car la réponse acceptée indique que c'est le bon moyen de partager la connexion). .

Sinon, vous pouvez consulter son code source et l'utiliser dans un autre cadre.

11
floatdrop

J'ai utilisé generic-pool avec des connexions redis dans mon application - je le recommande vivement. Son générique et je sais vraiment que cela fonctionne avec mysql, donc je ne pense pas que vous aurez de problèmes avec ça et mongo

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

6
ControlAltDel

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

Découvrez la source de Mongoose. Ils ouvrent une connexion et la lient à un objet Model. Ainsi, lorsque l'objet Model est requis, une connexion est établie avec la base de données. Le pilote prend en charge le regroupement des connexions.

4
srquinn

Vous devez créer une connexion en tant que service puis la réutiliser en cas de besoin.

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

mon exemple 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}`);
  });
});

et l'utiliser où vous voulez avec

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

J'ai implémenté le code ci-dessous dans mon projet pour implémenter le regroupement de connexions dans mon code afin de créer une connexion minimale dans mon projet et de réutiliser une connexion 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");

});
2
Aditya Parmar

La meilleure approche pour implémenter le regroupement de connexions consiste à créer une variable de tableau global contenant le nom de la base de données avec l’objet de connexion renvoyé par MongoClient, puis à réutiliser cette connexion chaque fois que vous devez contacter Database.

  1. Dans votre Server.js, définissez var global.dbconnections = [];

  2. Créez un service nommant connectionService.js. Il aura 2 méthodes getConnection et createConnection. Ainsi, lorsque l'utilisateur appellera getConnection (), il trouvera des détails dans la variable de connexion globale et renverra les détails de la connexion s'il existe déjà. Il appellera createConnection () et renverra les détails de la connexion.

  3. Appelez ce service en utilisant nom_base et il renverra un objet de connexion s'il en a déjà une autre, il créera une nouvelle connexion et vous le retournera.

J'espère que ça aide :)

Voici le code 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;
} 
1
RRPatel