5

What would be the most appropriate way of sharing the database connection in the below snippet ( the db variable) with my routers/controllers without turning the db variable into a global?

var mongo = require('mongoskin'),
db = mongo.db(config.db.adress);

app.use(function(req, res, next) {
    db.open(function(err, data) {
        (err) ? res.send('Internal server error', 500) : next();
    });
});

// Setting up controllers here
app.post('/users', require('./controllers/users').create);

Coming from a PHP background, I came to think about Dependency Injection, but I have no idea if that's appropriate in node.

Industrial
  • 41,400
  • 69
  • 194
  • 289
  • I don't see a problem??? It IS available inside the inner function already, in your example. If you don't specify a function inline but call one imported from another module instead, just give it to that function as parameter, possibly putting the call to that (external) fn inside an anonymous fn as already shown in your example. – Mörre Mar 14 '12 at 10:32
  • After your edit: give it to the function called from the "require"-d file as parameter (and make sure to actually use that param there, e.g. to set a module-global var to remember it for that module's other functions). Or, give it as parameter to any function who need DB access - which would be cleaner programming anyway (up to a point, that is). – Mörre Mar 14 '12 at 10:49
  • Well, sorry for the confusion. I updated the code in my question to contain an example of my routes/controller setup. There's no problem with the error handling, but I am still quite confused of what I should do to access the `db` object from inside the `users` controller, in this case, without first turning `db` into an global. – Industrial Mar 14 '12 at 10:50
  • Hi again. Not sure what you mean with *module-global*. Do you mind posting an answer showing your idea? – Industrial Mar 14 '12 at 10:52
  • Using your already existing example code, for that (main) module variables mongo and db are globally available for all other code you write *in the same file*. So at the top of your other module you *could* just declare another variable "db" and inside the create() function write the value received as parameter (which must have another name or it overwrites the outer-scope "db") into it. – Mörre Mar 14 '12 at 10:53
  • See http://openmymind.net/2012/2/3/Node-Require-and-Exports/ example "powerlevel" for how to "require" with a parameter given to the included module immediately. – Mörre Mar 14 '12 at 10:57

4 Answers4

7

Try look at this way:

app.js:

var mongo = require('mongoskin'),
db = mongo.db(config.db.adress);

app.use(function(req, res, next) {
    db.open(function(err, data) {
        (err) ? res.send('Internal server error', 500) : next();
    });
});

require('./controllers/users')(app, db);

controllers/users.js:

module.exports = function (app, db) {

    app.post('/users', function(req, res, next) {
        // Your create function
        // Link to db exists here
    });

};
Vadim Baryshev
  • 25,689
  • 4
  • 56
  • 48
  • 1
    I use this method as well. This is the best method so far short of replacing `require` logic. If there are lots of state to pass on, then instead of passing them one by one, you could pass in a hash object with all the required deps instead. – chakrit Aug 22 '12 at 12:27
  • You saved my day! – Nam Pham Oct 25 '16 at 11:07
5

I don't have any experience with mongoskin but Mongoose neatly sidesteps this problem by returning a Singleton instance of Mongoose every time you require it.

Which allows you to create a connection once (on app init, usually) and simply use it by querying Models when you need it.

It also allows you to define your models once like this:

var mongoose = require('mongoose'),

  TodoSchema = new mongoose.Schema({
    title: { 'type': String, 'default': 'empty todo...' },
    order: { 'type': Number },
    done: { 'type': Boolean, 'default': false }
  });

mongoose.model('Todo', TodoSchema);

And then use them wherever you need to like this:

  var mongoose = require('mongoose'),
      Todo = mongoose.model('Todo');

More information on how Mongoose works like this, with example code can be found in this answer here.

From mongoskin's docs, it looks like you have to connect each time you want to use it, which you could simplify by wrapping the db connection in a file you can require:

db.js

exports.db = require('mongoskin').db('myProject-' + process.env.NODE_ENV);

use it:

var db = require('./db');

db.open(function(err, data) {
        (err) ? res.send('Internal server error', 500) : next();
    });

The method above, where db is passed as an argument to every function that may need it, leads to callback soup and should be avoided if possible.

Community
  • 1
  • 1
Jed Watson
  • 20,150
  • 3
  • 33
  • 43
3

I ended up using Vadim Baryshev's answer and took it a bit further by creating a State module holding commonly used modules together, to keep things tidy:

state.js:

module.exports = {
    mongo: require('mongoskin'),
    db: require('mongoskin').db('myProject-' +process.env.NODE_ENV )
} 

app.js:

var state = require('./state');
require('./controllers/Users')(app, state);

controllers/users.js:

module.exports = function (app, state) {

    app.post('/users', function(req, res, next) {
        state.db.find({}, function(doc, err) {});
    });

};
Industrial
  • 41,400
  • 69
  • 194
  • 289
0

As suggested by @Jed Watson, the moongoose module uses a singleton (anti?) pattern, which is enforced by the require/export mechanism. Here is the specific bit of code :

(as found here : https://github.com/LearnBoost/mongoose/blob/master/lib/index.js)

/*!
 * The exports object is an instance of Mongoose.
 *
 * @api public
 */

var mongoose = module.exports = exports = new Mongoose;
nha
  • 17,623
  • 13
  • 87
  • 133