Is it possible to asynchronously initialize an export in a node.js module?

Since access and initialization of the MongoDB database is asynchronous in Node.js, I would like to define one module for each collection that exports wrapped db calls after db initialization.

Such a module "Cars.model.js" is as follows:

var db = require("mongodb"); db.collection("cars", function(err, col) { exports.getCars = function(callback) { col.find({}, callback); }; }); 

so that other modules can start:

 var carModel = require("Cars.model.js").getCars; getCars(err, cars) { // (do something with cars here...) }; 

It happened to me that getCars was undefined, because db access was not yet initialized at the time of launching my second module.

How do you deal with creating such asynchronous db models?

+8
asynchronous design-patterns model-view-controller mongodb
source share
3 answers

You cannot write exports after you left the file. You must block. To avoid blocking, I would use lazy resource loading.

 var carCol; var carEmitter = new require("events").EventEmitter; exports.getCars = function(callback) { // if no car collection then bind to event if (carCol === undefined) { carEmitter.on("cars-ready", function() { callback(carCol); }); } else { // we have cars, send them back callback(carCol); } } db.collection("cars", function(err, col) { // store cars carCol = col; // tell waiters that we have cars. carEmitter.emit("cars-ready"); }); 

Use event emitters to emulate lazy loading. You might want to generalize the LazyLoadedCollection class / object class to make the code faster / more DRY.

+10
source share

I'm new, so don't be mad at me ...

I use promises for this:

 var db = require("mongodb"), Q = require('q'), getCarsDefer = Q.defer(); exports.getCars = getCarsDefer.promise; db.collection("cars", function(err, col) { if(err){ getCarsDefer.reject(err); }else{ getCarsDefer.resolve(Q.ninvoke(col,'find')); }; }); 

So, you can get your cars as follows:

 var carModel = require("Cars.model.js").getCars; getCars.then(cars) { // (do something with cars here...) }; 

This is a bad idea, please let me know, because this is what I am doing right now.

+2
source share

I believe this simple solution works: replace the asynchronous call with getCars() synchronous call to the collection cache, which will be populated before the models are called.

The start module of the main.js application:

 var db = require("mongodb"); exports.collectionCache = {}; db.collection("cars", function(err, col) { exports.collectionCache["cars"] = col; // ready => start application logic (incl. models) here }); 

Thus, "Cars.model.js" will look like this:

 var col = require("main").collectionCache; // populated exports.getCars = function(callback) { col["cars"].find({}, callback); }; 

This solution moves the asynchronous problem from models to the root database model, which simplifies model development.

0
source share

All Articles