Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I structure my express app where I only need to open a mongodb connection once?

Note: Please read the edited portion of this post before answering, it might save you time and answers one of my questions.

The problem I'm having is pretty simple but I'm pretty new to this overall and I'm having issues figuring out how to implement a mongodb database connection properly in a node/express app.

I'm using express 3.x and am basing my app layout around this project supplied by the author of Express: https://github.com/expressjs/express/tree/d8caf209e38a214cb90b11ed59fd15b717b3f9bc/examples/blog (now removed from repo)

I have no interest in making a blog however the way the app is structured appears to be quite nice. The routes are separated and everything is organized nicely.

My problem is I might have 5-6 different route js files and each route js file might have anywhere between 1 and 15 routes; of those routes 1 or 15 might want to access the db.

So my problem is it seems like a really terrible idea to do a db.open(...) every single time I want to query the db. I should mention at this point I'm using the native mongo-db driver (npm install mongodb).

I would also need to include a file like this: http://pastebin.com/VzFsPyax

...in all of those route files and all of my model files. Then I'm also dealing with dozens upon dozens of open connections.

Is there a way I can structure my app in such a way where I only make 1 connection and it stays open for the duration of the session (having a new one made every request would be bad too)?

If so, how can I do this? If you know the answer please post a code sample using tj's blog app (the one linked earlier in this post) structure as a base guide. Basically have a way where the routes and models can use the db freely while being in separate files than the db open code.

Thanks.

EDIT

I made some progress on solving one of my issues. If you look at tj's blog example he initializes his routes in the app.js like so:

require('./routes/site')(app);
require('./routes/post')(app);

And in the routes js file it starts like this:

module.exports = function(app){

I stumbled on a project earlier today where I saw someone pass 2 variables in the modules.exports call -> function(app, db). Then figured wow could it be that easy, do I need to just adjust my routes to be (app, db) too? Yeah, it seems so.

So now part 1 of the problem is solved. I don't have to require a mongo.js file with the connection boilerplate in every route file. At the same time it's flexible enough where I can decide to pick and choose which route files pass a db reference. This is standard and has no downside right?

Part 2 of the problem (the important one unfortunately) still exists though.

How can I bypass having to do a db.open(...) around every query I make and ideally only make a connection once per session?

like image 687
AntelopeSalad Avatar asked Mar 10 '12 23:03

AntelopeSalad


3 Answers

Other solution is to pass database to the router via request, like this:

app.js

var db = openDatabase();

var app = express();

app.all('*', function(request, response, next)
    {
    request.database = db;
    next();
    });

app.get('/api/user/:id', Users.getByID);

users.js

var Users =
    {
    getByID: function(request, response)
        {
        request.database.collection('users').findOne(...)
        response.send(user);
        }
    };

module.exports = Users;
like image 79
Fabrice Theytaz Avatar answered Sep 21 '22 23:09

Fabrice Theytaz


I made a very simple module hub for this case that replaces the use of a global space.

In app.js you can create db connection once:

var hub = require('hub');
hub.db = new Db('foobar', new Server('10.0.2.15', 27017, {}), {native_parser: false});

And use it from any other files:

var hub = require('hub');
// hub.db - here link to db connection

This method uses a feature of 'require'. Module is only loaded for the first time and all the other calls gets a reference to an already loaded instance.

UPDATE

That's what I mean:

In main file like app.js we create Db connection, open it and store into hub:

app.js:

var hub = require('hub');
hub.mongodb = require('mongodb');
hub.mongodbClient = new hub.mongodb.Db('foobar', new hub.mongodb.Server('10.0.2.15', 27017, {}), {native_parser: false});
hub.mongodbClient.open(function(error) {
    console.log('opened');
});

Now in any other file (message for example) we have access to opened connection and can simple use it:

message.js:

var hub = require('hub');
var collection = new hub.mongodb.Collection(hub.mongodbClient, 'message');

module.exports.count = function(cb) {
    collection.count({}, function(err, count) {
        cb(err, count);
    });
};
like image 21
Vadim Baryshev Avatar answered Sep 24 '22 23:09

Vadim Baryshev


Really silly. In the documentation it seems like db.open requires to be wrapped around whatever is using it, but in reality you can use it without a callback.

So the answer is to just do a db.open() in your database connection module, app.js file or where ever you decide to setup your db server/connection.

As long as you pass a reference to the db in the files using it, you'll have access to an "opened" db connection ready to be queried.

like image 34
AntelopeSalad Avatar answered Sep 24 '22 23:09

AntelopeSalad