Search code examples
javascriptnode.jsnode-mongodb-native

Multiple files requiring my module are overwriting it's variables


I'm trying to create a mongo connection pool factory that checks if a connection to mongo already exists and returns a connection. If it doesn't create the connection pool and return a connection.

I want to be able to require this from multiple files that are going to query mongo. Each file should require mongo like this:

var fooMongoFactory = require('../../lib/mongoFactory').init(mongodb://localhost:27017/foo);

and then you use it in your file like this:

fooMongoFactory.getConnection().then(function(db) {
  // do stuff
});

The problem i'm having is that I want to be able to specify multiple different mongo instances in a file, but when doing that, my second init overrides the first one. Example:

var fooMongoFactory = require('../../lib/mongoFactory').init(mongodb://localhost:27017/foo);
var barMongoFactory = require('../../lib/mongoFactory').init(mongodb://localhost:27017/bar);

fooMongoFactory.getConnection().then(function(db) {
  // querying in here is actually pointing at the mongo db "bar"
});

How can I tweak my factory so that I can connect to multiple different instances of mongo, as well as use this same factory across multiple files without having to instantiate it every time? I thought of using a constructor, but that would create a new connection pool in every single file that uses the mongoFactory.

/**
 * Creates and manages the Mongo connection pool
 *
 * @type {exports}
 */
var Q = require('q');
var MongoClient = require('mongodb').MongoClient;
var dbPromise = null;
var db = null;

module.exports = function() {

  return {

    init: function init(connectionString) {
      db = connectionString;
      return module.exports;
    },

    /**
     * Gets a connection to Mongo from the pool. If the pool has not been instantiated it,
     *    instantiates it and returns a connection. Else it just returns a connection from the pool
     *
     * @returns {*}   - A promise object that will resolve to a mongo db object
     */
    getConnection: function getConnection() {
      // get a connection to mongo using the db string and return dbPromise 
    }
  }
}();

Solution

  • I ended up making the module so that you have to pass in the connection string for the mongodb that you want to connect to. This module ultimately keeps track of all the connections that have been made to mongo and whether there is a current connection to the mongodb passed in or not.

    /**
     * Creates and manages the Mongo connection pool
     *
     * @type {exports}
     */
    var Q = require('q');
    var MongoClient = require('mongodb').MongoClient;
    var _ = require('underscore');
    
    var connections = [];
    var dbPromise = null;
    
    module.exports = function() {
    
      return {
    
        /**
         * Gets a connection to Mongo from the pool. If the pool has not been instantiated it,
         *    instantiates it and returns a connection. Else it just returns a connection from the pool
         *
         * @returns {*}   - A promise object that will resolve to a mongo db object
         */
        getConnection: function getConnection(connectionString) {
    
          var def = Q.defer();
    
                // If connectionString is null or undefined, return an error
                if(_.isEmpty(connectionString)) {
                    def.reject('getConnection must contain a first parameter');
                    return dbPromise = def.promise;
                }
    
          // Check if connections contains an object with connectionString equal to the connectionString passed in and set the var to it
          var pool = _.findWhere(connections, {connectionString: connectionString});
    
          // If no conneciton pool has been instantiated, instantiate it, else return a connection from the pool
          if(_.isUndefined(pool)) {
    
            // Initialize connection once
            MongoClient.connect(connectionString, function(err, database) {
              if (err) {
                def.reject(err);
              }
    
              // Add the connection to the array
              connections.push({connectionString: connectionString, db: database});
    
              def.resolve(database);
            });
    
          } else {  // Else we have not instantiated the pool yet and we need to
            def.resolve(pool.db);
          }
    
          return dbPromise = def.promise;
        }
      };
    }();
    

    https://github.com/toymachiner62/mongo-factory