I wrote my 1st application in Node.js with MongoDB and I came across the situation where I need to have 2 db.collection.update
statements depending on an IF/ELSE condition.
I am trying to return back the operation details in a resJSON
JS object but seems like callback is executing before the db.collection.update
statements are completed and the default value of resJSON
is getting back in response each time.
detail code:
var url = require('url');
var fs = require('fs');
var async = require('async');
var passwordGen = require('../../lib/passwordGen');
var http = require("http");
var server = http.createServer();
server.on('request', request);
server.listen(8080,'127.0.0.1');
function request(request, response) {
var userData = '';
request.on('data', function(data)
{
userData += data;
});
request.on('end', function()
{
async.auto({
allProcess: function(callback){
var resJSON = {'inserted':0,'disabled':0,'error':''};
var jsonData = JSON.parse(userData);
if(jsonData.length > 0){
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/test_db", function(err,db){
if(err) { return console.dir(err); }
var collection = db.collection('users');
var arrDisableRec = [];
for(i=0;i<jsonData.length;i++){
var action = jsonData[i]['action'].toLowerCase();
if(action == 'disable'){
arrDisableRec.push(jsonData[i]['email']);
}else{
var date = new Date();
var obj = {
'createdISO':date,
'created':date,
'updated':date,
'updatedISO':date,
'email':jsonData[i]['email'],
'firstName':jsonData[i]['firstname'],
'lastName':jsonData[i]['lastname'],
'password':passwordGen.getPassword(),
'enabled':true,
'active':true,
'downloaded':true,
'defaultServings':2,
'name':''
};
collection.update(
{'email':jsonData[i]['email']},
{$setOnInsert:obj},
{upsert: true},
function(err,numberAffected,rawResponse) {
if(typeof numberAffected.result.upserted != 'undefined'){
resJSON['inserted'] = resJSON['inserted'] + numberAffected.result.upserted.length;
}
if(typeof numberAffected.result.nModified != 'undefined'){
resJSON['disabled'] = resJSON['disabled'] + parseInt(numberAffected.result.nModified);
}
if(typeof numberAffected.result.writeError != 'undefined'){
resJSON['error'] ='Error Code:'+(numberAffected.result.writeError.code)+', '+numberAffected.result.writeError.errmsg;
}
console.log(resJSON); //shows correct values
}
);
}
if(arrDisableRec.length > 0){
collection.update(
{'email':{$in:arrDisableRec}},
{$set:{'enabled':false}},
{multi:true},
function(err,numberAffected,rawResponse) {
if(typeof numberAffected.result.upserted != 'undefined'){
resJSON['inserted'] = resJSON['inserted'] + numberAffected.result.upserted.length;
}
if(typeof numberAffected.result.nModified != 'undefined'){
resJSON['disabled'] = resJSON['disabled'] + parseInt(numberAffected.result.nModified);
}
if(typeof numberAffected.result.writeError != 'undefined'){
resJSON['error'] ='Error Code:'+(numberAffected.result.writeError.code)+', '+numberAffected.result.writeError.errmsg;
}
console.log(resJSON); //shows correct values
}
);
}
}
});
}
callback(resJSON);
}
},function(resJSON){
response.writeHead(200,{
'Content-Type': 'text/json'
});
response.end(JSON.stringify(resJSON)); //replies back with default resJSON only.
});
});
}
Any suggestions/directions please?
Thanks
You have to call the callback at then end of the callback chain.
For example
you will have to make sure that every callback chain end point calls the callback. To handle the for loop you will have to have a mechanism to join all the end points of all the async calls done inside the for loop.
for example
notice that I used the
function callback(err, res)
standard node prototype instead of yourfunction callback(res)
better yet, use an async flow library like
async
or a promise library likebluebird