0

I'm adding MongoDB to my Express.js Node web app. This is what I got so far:

// in app.js
var mongodb = require('mongodb');
var mongourl = /* … */;

// These are just examples:

app.get('/write', function (req, res) {
    mongodb.connect(mongourl, function (err, db) {
        db.collection('Users', function (err, coll) {
            coll.insert(/* stuff */, function (err) {
                res.send(200, 'Done.');
            });
        });
    });
});

app.get('/read', function (req, res) {
    mongodb.connect(mongourl, function (err, db) {
        db.collection('Users', function (err, coll) {
            coll.find({}, function (err, cursor) {
                cursor.toArray(function (err, items) {
                    res.send(200, items);   
                });             
            });
        });
    });
});

Assuming that I want to stick with the default mongodb driver (for now):

  1. Is this pattern right? Do I have to open a new connection to the database in each of my different routes that perform database operations?

  2. If the pattern is right, then how do I deal with the obvious code repetition going on here? Obviously, as it stands now, the code is not acceptable.

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385

2 Answers2

2

Use the new standard, MongoClient. It manages the pool for you, defaults to 5.

  //require as a module to be used anywhere.

  module.exports = {}  

  var MongoClient = require('mongodb').MongoClient;
  var mongoURI = /* … */;

  MongoClient.connect(mongoURI, function(err, db) {
    if(err) throw err;

    module.exports.users = db.collection('users');

    console.log('Connected to Mongo!')

  })

then

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

//once connected

//db.users.find()... etc

check out: http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

pooling details: http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#connection-pool-configuration

boom
  • 10,856
  • 9
  • 43
  • 64
  • So, basically the mongodb API does not support promises? This assign global variable from within async callback doesn't look good. – Šime Vidas Jan 05 '14 at 20:52
  • What do you mean, it's not global -- but yeah you need to wait for the database to connect before you can use it... – boom Jan 05 '14 at 20:52
  • The outer scope variable is assigned to from within the inner scope callback. If that's the standard approach, good, but I don't like this pattern. Promises would be better, i.e. `var db = MongoClient.connect(...);`. – Šime Vidas Jan 05 '14 at 20:54
  • Disagree that promises would be better. – boom Jan 05 '14 at 20:55
  • Regarding the exporting, how would I export the `db` value which only becomes available in the async callback? – Šime Vidas Jan 05 '14 at 20:56
  • I also don't see why promises would be better. If you're really strict you can move your Express code (or at least the call to `listen`) into the callback function, but you'd have to do that for promises too. – robertklep Jan 05 '14 at 20:56
  • @robertklep In my code in the question above, there are four nested callback functions within `.connect()`. That's certainly not the optimal code pattern. Promises fix that. – Šime Vidas Jan 05 '14 at 20:59
  • @ŠimeVidas yes but we're talking about connection pooling here, which means that the call to `connect` only happens once, during app initialization. From there you can reuse the exported `db` value. – robertklep Jan 05 '14 at 21:01
  • I put your code inside a db.js file and required it in my app.js: `var db = require('./db');`. Now, when I try to perform `db.collection()`, an error is thrown: `TypeError: Object # has no method 'collection'`. It seems that the nested `module.exports` assignment in your code isn't reflected in app.js's `db` variable. – Šime Vidas Jan 05 '14 at 21:18
  • @boom Yes. I got the `console.log` message and only then did I access the page in the browser. – Šime Vidas Jan 05 '14 at 21:22
  • @ŠimeVidas working? you could also attach the db object to `module.exports.mongo = db` or something if you need the raw instance. – boom Jan 06 '14 at 14:37
  • @boom I decided to switch to the "mongojs" module instead. In db.js: `var db = require('mongojs')(/* URL */, ['users']); module.exports = db;`. In app.js: `var db = require('./db');`, and then: `db.users.find(…`. Works and happy with it. – Šime Vidas Jan 06 '14 at 15:05
  • @ŠimeVidas Same difference, that's just a lib that does this for you. All you would need to do is make the export a function that returns db. My answer is still correct for this question... – boom Jan 06 '14 at 17:32
0

Do not close and reopen connection, you're just loosing resources :s

farvilain
  • 2,552
  • 2
  • 13
  • 24