10

I am working on a nodejs / mongodb app using 'mongodb' module. The app is launched with

node main.js

In main.js, I connect to the db and keep the connection in the 'db' global variable. 'db' is then used in inner methods of 'server'. I want to avoid having 'db' as a global variable but did not found the correct way to do.

My current main.js:

var server      = require('./lib/server');
var MongoClient = require('mongodb').MongoClient;
var Server      = require('mongodb').Server;
var mongoClient = new MongoClient(new Server(HOST, PORT));
db = null;

// Database connection
mongoClient.open(function(err, mongoClient) {
  if(!err){
    // Database selection
    db = mongoClient.db(DB);

    // Launch web server
    server.start(); // usage of 'db' in this part 

  } else {
    console.log(err.message);
    process.exit(1);
  }
});

Any idea of a cleaner way ?

UPDATE

I finally created a module in connection.js:

var config      = require('../config/config');
var url         = 'mongodb://' + config.db.host + ':' + config.db.port + '/' + config.db.name;
var MongoClient = require('mongodb').MongoClient;
var db          = null;

module.exports = function(cb){
  if(db){
    cb(db);
    return;
  }

  MongoClient.connect(url, function(err, conn) {
    if(err){
      console.log(err.message);
      throw new Error(err);
    } else {
      db = conn; 
      cb(db);
    }
  });
}

Each time I need to get the connection I call:

var connection = require('./connection');
connection(function(db){
  // doing some stuff with the db
});

This is working very well.

Any potential failure with this approach ?

5
  • 1
    Pass it to whatever modules are using it in a constructor (Constructor dependency injection) or have a module that contains that instance and have other modules require it and ask for the db instance and other services they require (service location) (generally worse) Commented Aug 1, 2013 at 22:00
  • if you really plan to stay with globals, I'd indicate to use global.db instead. At least, isn't invalid JS. Commented Aug 1, 2013 at 22:01
  • I'd like to get rid of this global :) Commented Aug 1, 2013 at 22:08
  • @Luc I'm in same spot. I'm not sure but I believe node doesn't re-load a module already loaded once by require. But I don't want to use this feature as a globals mechanism. There must be some other way. Commented Aug 2, 2013 at 12:01
  • @S.D. You're right, re-loading a module doss not load it once again. In the approach I use, I require the module and call the function so it returns the db in the calback. The connection module acts as a kind of Singleton. Commented Aug 2, 2013 at 20:15

2 Answers 2

6

I typically include a project utilities file that contains a number of these things, just to make it easy. It functions as a pseudo global, but without many of the usual problems globals entail.

For example,

projectUtils.js

module.exports = {

  initialize: function(next){
    // initialization actions, there can be many of these
    this.initializeDB(next);
  },

  initializeDb: function(next){
    mongoClient.open(function(err, mongoClient) {
      if(err) return next(err);
      module.exports.db = mongoClient.db(DB);
      next();
    });
  }
}

app.js

var projectUtils = require('projectUtils');

// (snip)
projectUtils.initialize(function(err) {
  if(err) throw err; // bad DB initialization
  // After this point and inside any of your routes,
  // projectUtils.db is available for use.
  app.listen(port);
}

By using an asynchronous initialize() function, you can be sure that all database connections, file I/O, etc., are done before starting up the server.

Sign up to request clarification or add additional context in comments.

Comments

3

You can create a wrapper something like a provider and put it in provider.js, for instance.

Provider = function (db_name, host, port, username, password) {
    var that = this;
    var conn = generate_url(db_name, host, port, username, password); // you need to implement your version of generate_url()

    MongoClient.connect(conn, function (err, db) {
        if (err) {
            throw err;
        }
        that.db = db;
    });
};

//add the data access functions
Provider.prototype.getCollection = function (collectionName, callback) {
    this.db.collection(collectionName, collectionOptions, callback);
};

exports.Provider = Provider;

This is how you use the provider:

var db = new Provider(db_name, host, port, username, password);
db.getCollection('collection name', callback);

1 Comment

Can you be sure the connection is done (callback method called) before using it calling db.getCollection ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.