0

need a little assistance with an understanding nodejs code organization, so I'm from C++ world and suppose that didn't understand a principles.

So I need to implement some js module which should connect to MongoDB and exports a few methods for other modules: e.g. insert, update, delete.

when I write something like:

var db = MongoClient.connect(config.connectionString, {native_parser:true},function (err, db) {...});

exports.insert = function(a, b) {
    // db using
    //...
};

I suppose that "db" local static variable and will be initialized in any case. at the time of call "require('this module') " but seems it's not so, and db is uninitialized at the time of the call of exported functions? another question - I suppose this should be implemented using "futures" (class from c++, didn't find an analogue from js) to guaratee that db object is copmpletely constructed at the moment of the using??

amigo421
  • 2,429
  • 4
  • 26
  • 55
  • why do you think DB is uninitialized? – Sharjeel Ahmed Feb 27 '17 at 10:44
  • had a look at this in debugger, that was null. anyway I'd prefer to organize a code of a callbacks, to guarantee complete initialization – amigo421 Feb 27 '17 at 10:46
  • its not possible db is uninitialized, because db is a closure variable. http://stackoverflow.com/questions/111102/how-do-javascript-closures-work My guess is that db is is failing to initialize in the first line itself. – Sharjeel Ahmed Feb 27 '17 at 10:48
  • got it. thank you. going to re-check in details – amigo421 Feb 27 '17 at 10:52
  • ok also since you are from the C++ background, I suggest you read up on closures in Javascript. – Sharjeel Ahmed Feb 27 '17 at 10:54
  • At what point? put a breakpoint at var db = MongoClient.connec.... ? and step over and see what is the value of DB? – Sharjeel Ahmed Feb 27 '17 at 11:02
  • I was little bit wrong, actually: at the exported method of the using db variable, e.g. insert, db is void, and the atttempt to get a .collection property raise an exception – amigo421 Feb 27 '17 at 11:06
  • by the way: debugger doesn't show db variable in all sections: local, global, closure – amigo421 Feb 27 '17 at 11:07
  • so my guess is that db is null because the output of var db = MongoClient.connec... is null. if debugger does not show you, put console.log(db) after your var db= ... line and see what the console displays. – Sharjeel Ahmed Feb 27 '17 at 11:08
  • do you suppose me to use something like: var db; MongoClient.connect(config.connectionString, {native_parser:true},function (err, db) {...}); – amigo421 Feb 27 '17 at 11:09
  • I know connect doesn't return db object, but this is in a parameter list, and I supposed that passed by ref and filled up with a real object then – amigo421 Feb 27 '17 at 11:10
  • console log : undefined. too. you can suppose that is a wrong connection but this is a valid connection, because it works fine if I open/close this connection inside the method. – amigo421 Feb 27 '17 at 11:13

2 Answers2

0

I had worked with C++, Java before (sometime back, not now) and now working in nodejs. I think I understood your question. Here are some key points.

  1. Yes, Nodejs modules are somewhat like classes that they encapsulate the variables and you access only through public methods (exposed through exports). I think you are aware that there is no class implementation at all here, but it loosely maps to the behaviour.

  2. The key difference in nodejs is the asynchronous nature of resource instantiation. By this, I mean if there are 2 statements stmt1 and stmt2, if stmt1 is called and takes time, nodejs does not wait for it to end (that is synchronous behaviour), instead it moves on to stmt2. In pre-nodejs world, we assume that reaching stmt2 means stmt1 is complete.

  3. So, what is the workaround? How to ensure you do something after db connection is obtained. If your code is not making db calls immediately, you could assume that connection will be through. Or if you immediately want to invoke db, you write the code on a callback. Mongo exposes events called 'open' and 'error'. You can use this to ensure connection is open. Also it is best practise to track error event.

    db.on('error', console.error.bind(console, 'connection error'));

    db.once('open', function callback() { console.log("Connection with database succeeded."); // put your code });

I am not aware of C++ future and so cannot comment on that.

Hope this helps !

[Updated] To add example

You could have db.js for setting up db connection and expose Mongoose object to create models.

'use strict';

var Mongoose = require('mongoose'),
        Config = require('./config');

Mongoose.connect(Config.database.url);

var db = Mongoose.connection;

db.on('error', console.error.bind(console, 'connection error'));

db.once('open', function callback() {
    console.log("Connection with database succeeded.");
});

exports.Mongoose = Mongoose;
exports.db = db;

You can include db.js in the server.js like

var DB = require('db.js');

which will do the initialisation.

You then use mongoose (mongoose is a Object relational mapper to work with mongo and highly recommended) to get models of database objects as shown below.

//userModel.js

var mongoose = require('mongoose'),
    Schema = mongoose.Schema,

var UserSchema = new Schema({
    uid : {type : Number,  required: false}
    , email : {type : String, get: toLower, set: toLower,  required: true, index: { unique: true } }
    , passwd : {type : String,  required: false}
); 

var user = mongoose.model('user', UserSchema);

module.exports = {
  User : user
};

For more information on mongoose, you can refer http://mongoosejs.com

The db is generally not closed as I use in web environment and is always on. There is db connection pooling maintained and connections are reused optimally. I saw noticed a thread in SO which adds more details. Why is it recommended not to close a MongoDB connection anywhere in Node.js code?

Community
  • 1
  • 1
Kannan J
  • 508
  • 5
  • 12
  • thank you. could you extend your post with an example, please? because currently , if I'm initializing db outside of the methods, its void. inside the methods - works fine. and - yes, I don't require the using of db immediately after the connect – amigo421 Feb 27 '17 at 11:22
  • Sure, will add now. – Kannan J Feb 27 '17 at 11:25
  • thank you! by the way - could you also describe - what is a best practice to release the resources? I mean where and how to db.close() in my case? – amigo421 Feb 27 '17 at 11:31
  • @amigo421, added helpful code. Let me know if this is what you were looking for. Cheers – Kannan J Feb 27 '17 at 11:43
0

So the problem I see is that you want to use DB but since DB is returned async, it may or may not be available in the exported function, hence you need to convert the connect from async to sync.

Since MongoDB driver cannot do sync, i suggest you use a wrapper, i suggest mongoskin.

https://github.com/kissjs/node-mongoskin

var mongo = require('mongoskin');
var db = mongo.db(config.connectionString, {native_parser:true});

Now this should work for you.

Sharjeel Ahmed
  • 2,051
  • 2
  • 17
  • 25