How do I manage MongoDB connections in a Node.js w

2018-12-31 07:14发布

I'm using the node-mongodb-native driver with MongoDB to write a website.

I have some questions about how to manage connections:

  1. Is it enough using only one MongoDB connection for all requests? Are there any performance issues? If not, can I setup a global connection to use in the whole application?

  2. If not, is it good if I open a new connection when request arrives, and close it when handled the request? Is it expensive to open and close a connection?

  3. Should I use a global connection pool? I hear the driver has a native connection pool. Is it a good choice?

  4. If I use a connection pool, how many connections should be used?

  5. Are there other things I should notice?

10条回答
千与千寻千般痛.
2楼-- · 2018-12-31 07:18

The primary committer to node-mongodb-native says:

You open do MongoClient.connect once when your app boots up and reuse the db object. It's not a singleton connection pool each .connect creates a new connection pool.

So, to answer your question directly, reuse the db object that results from MongoClient.connect(). This gives you pooling, and will provide a noticeable speed increase as compared with opening/closing connections on each db action.

查看更多
何处买醉
3楼-- · 2018-12-31 07:22

Best approach to implement connection pooling is you should create one global array variable which hold db name with connection object returned by MongoClient and then reuse that connection whenever you need to contact Database.

  1. In your Server.js define var global.dbconnections = [];

  2. Create a Service naming connectionService.js. It will have 2 methods getConnection and createConnection. So when user will call getConnection(), it will find detail in global connection variable and return connection details if already exists else it will call createConnection() and return connection Details.

  3. Call this service using db_name and it will return connection object if it already have else it will create new connection and return it to you.

Hope it helps :)

Here is the connectionService.js code:

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;
} 
查看更多
与君花间醉酒
4楼-- · 2018-12-31 07:23

Here is some code that will manage your MongoDB connections.

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;

When you start the server, call initPool

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

Then in any other module you can do the following:

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

This is based on MongoDB documentation. Take a look at it.

查看更多
高级女魔头
5楼-- · 2018-12-31 07:23

If you have Express.js, you can use express-mongo-db for caching and sharing the MongoDB connection between requests without a pool (since the accepted answer says it is the right way to share the connection).

If not - you can look at its source code and use it in another framework.

查看更多
妖精总统
6楼-- · 2018-12-31 07:31

Manage mongo connection pools in a single self contained module. This approach provides two benefits. Firstly it keeps your code modular and easier to test. Secondly your not forced to mix your database connection up in your request object which is NOT the place for a database connection object. (Given the nature of JavaScript I would consider it highly dangerous to mix in anything to an object constructed by library code). So with that you only need to Consider a module that exports two methods. connect = () => Promise and get = () => dbConnectionObject.

With such a module you can firstly connect to the database

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

When in flight your app can simply call get() when it needs a DB connection.

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

If you set up your db module in the same way as the following not only will you have a way to ensure that your application will not boot unless you have a database connection you also have a global way of accessing your database connection pool that will error if you have not got a connection.

// 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;
}
查看更多
唯独是你
7楼-- · 2018-12-31 07:34

Open a new connection when the Node.js application starts, and reuse the existing db connection object:

/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: How to Open Database Connections in a Node.js/Express App

查看更多
登录 后发表回答