Using argument of function in Node's module async - node.js

I learn Node.js and doing a small site guided by MDN.
I reached to place where there using module async.
This is code
async.parallel({
book_count: function(callback) {
Book.countDocuments({}, callback); // Pass an empty object as match condition to find all documents of this collection
},
book_instance_count: function(callback) {
BookInstance.countDocuments({}, callback);
},
book_instance_available_count: function(callback) {
BookInstance.countDocuments({status:'Available'}, callback);
},
author_count: function(callback) {
Author.countDocuments({}, callback);
},
genre_count: function(callback) {
Genre.countDocuments({}, callback);
}
}, function(err, results) {
res.render('index', { title: 'Local Library Home', error: err, data: results });
});
};
This code count number documents in the database.
I don't understand what is argument "callback". There have nothing sent in these properties "book_count, book_instance_count, author_count, etc.." but all of these function work excellent.
Please, explain to me , what is odd argument "callback" and how to use it.

Callback function
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greeting);
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function

Related

async in node js is not working

I am trying to run two different mongoose queries and display the result in same ejs page. I searched a lot and finally found the async method. How I tried this is below.
js file
router.get('/CreateSurvey', function(req, res, next) {
async.parallel([
function(callback) {
QBank.find( function ( err, classes, count ){
classes : classes
});
},
function(callback) {
QBank.findOne({_id:"H001"}, function ( err, questions, count ){
questions : questions
});
}
], function(err) {
if (err) return next(err);
res.render('CreateSurvey', QBank);
});
});
But when I refresh '/CreateSurvey' page it does not render. I have already downloaded async module and required in my js file. Where am I wrong?
Firstly, What is that classes : classes and questions : questions lines in your code? What are you trying to do?
The callback parameter of each task function (the functions in array) should be called inside the task to indicate completion of each task with success or error.
The optional main callback (the third function in your code), where you are doing the actual rendering, will be called only after all the tasks have completed.
In your code callback is not called inside the task. As a result the final callback is also never getting called. In fact, in your code only the first *task gets executed and nothing happens beyond that.
Read more about async.parallel in documentation
There are some issues with the code, you aren't calling callback corresponding to async call. Try the following:
router.get('/CreateSurvey', function(req, res, next) {
async.parallel({
classes: function(callback) {
QBank.find(function(err, classes, count){
callback(classes);
});
},
questions: function(callback) {
QBank.findOne({_id:"H001"}, function (err, questions, count ){
callback(questions);
});
}
}, function(err, result) {
if (err) return next(err);
res.render('CreateSurvey', result); // { classes : [c1, c2] , questions : [q1, q2] }
});
});

Nodejs assign var once mongodb query finished (callback misunderstanding needing a simple example)

I'm calling a mongodb query and need to assign the result to a value.
function oneref(db, coll, cb) {
var pipeline = [{ "$sample": { size: 1 } }]
var ohoh
coll.aggregate(pipeline, function (err,oneref) {
ohoh=oneref[0].code
})
console.log('hoho?: ' + ohoh)
cb(null, db, coll)
},
I understand I have an issue understanding callback, but even checking all hello world examples, I'm struggling.
How to write it in the simplest way so I only assigne the var hoho when the query finished?
Thanks a lot in advance.
You're getting undefined value for the variable hoho is because the aggregate() cursor method is asynchronous, and can finish at any time. In your case, it is finishing after you're using console.log(), so the values are undefined when you're accessing them.
Asign the variable as the argument to the callback within the aggregate() function callback i.e.
function oneref(db, coll, cb) {
var pipeline = [{ "$sample": { size: 1 } }];
coll.aggregate(pipeline, function (err, oneref) {
if (err) return cb(err);
var hoho = oneref[0].code
console.log('hoho?: ' + hoho);
cb(null, hoho);
});
};
Calling the oneref function:
oneref(db, collection, function(err, result){
console.log(result); // logs the oneref[0].code
});
Refer to this Question for a better understanding on how callback functions work.

node js + async parallel + function call method not working

I have functions in different place.(this is common function it will use many place.
So I tried to call the function using async parallel but its not working.
I attached the my code following:L
var userId = 33;
async.parallel({
video(userId, callback) {
callback(null, callback);
},
video1(userId, callback) {
callback(null, callback);
}
}, function(err, results) {
console.log(results);
});
function video (userId, callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video) {
callback(err, video);
});
}
function video1(userId, callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource1 order by random() limit 1 ", function(err, video1) {
callback(err, video1);
});
}
The {fnName()} syntax is a function declaration. You want to use a function call ... in fact you can just use async.parallel({video, video1}, (err, results) => console.log(results) to achieve the same effect... except that you also need to pass in userId. So what you actually intend is to call the function rather than declare it:
async.parallel([
callback => video(userId, callback),
]);
You need to pass function references to async.parallel() and you need to pass an array, not an object. You want the code to have this form:
async.parallel([fn1, fn2], finalCallback);
See the async.parallel() doc here for specific examples of the syntax you want to use.
Where fn1, fn2 and finalCallback are all function references that can be called by the async.parallel() infrastructure, not something you call yourself.
Change your code to this:
async.parallel([
function(callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video) {
callback(err, video);
}),
},
function(callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video1) {
callback(err, video1);
});
}
], function(err, results) {
console.log(results);
});
Presumably, your two database queries should be different somehow (your code showed them identical).
If your functions are already defined somewhere, then you can pass an anonymous function reference that will call them. You need to do this if your functions don't have the exact same calling convention that async.parallel() requires. You can do that like this:
async.parallel([function(callback) {
video(userId, callback);
}, function(callback) {
video1(userId, callback);
}], function(err, results) {
console.log(results);
});

Make Node.js code synchronous in Mongoose while iterating

I am learning Node.js; due to asynchronous of Node.js I am facing an issue:
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
for(var i=0;i<result.length;i++){
console.log("result is ",result[i].id);
var camera=null;
domain.Cameras.count({"userId": result[i].id}, function (err, cameraCount) {
if(result.length-1==i){
configurationHolder.ResponseUtil.responseHandler(res, result, "User List ", false, 200);
}
})
}
})
I want to use result in Cameras callback but it is empty array here, so is there anyway to get it?
And this code is asynchronous, is it possible if we make a complete function synchronous?
#jmingov is right. You should make use of the async module to execute parallel requests to get the counts for each user returned in the User.find query.
Here's a flow for demonstration:
var Async = require('async'); //At the top of your js file.
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
var cameraCountFunctions = [];
result.forEach(function(user) {
if (user && user.id)
{
console.log("result is ", user.id);
var camera=null; //What is this for?
cameraCountFunctions.push( function(callback) {
domain.Cameras.count({"userId": user.id}, function (err, cameraCount) {
if (err) return callback(err);
callback(null, cameraCount);
});
});
}
})
Async.parallel(cameraCountFunctions, function (err, cameraCounts) {
console.log(err, cameraCounts);
//CameraCounts is an array with the counts for each user.
//Evaluate and return the results here.
});
});
Try to do async programing allways when doing node.js, this is a must. Or youll end with big performance problems.
Check this module: https://github.com/caolan/async it can help.
Here is the trouble in your code:
domain.Cameras.count({
"userId": result[i].id
}, function(err, cameraCount) {
// the fn() used in the callback has 'cameraCount' as argument so
// mongoose will store the results there.
if (cameraCount.length - 1 == i) { // here is the problem
// result isnt there it should be named 'cameraCount'
configurationHolder.ResponseUtil.responseHandler(res, cameraCount, "User List ", false, 200);
}
});

nodejs, mongodb-update, async, callback is not consider as a function

I have a problem with the code below. Everything goes fine, until the db.collection.update.
At at console.log(n.6), the callback is not consider as a function anymore. And I don't understand why.
The console display:
callback(errorCode404)
TypeError: object is not a function
var newData = req.body;
...
async.waterfall([
function(callback){
console.log('n3');
db.getConnection(callback);
},
function(db, callback){
console.log('n4');
db.collection('dossiers', callback);
},
function(dossiers, callback){
console.log('n5');
dossiers.update({'_id': mongodb.ObjectID(id)}, {$set:newData}, callback);
},
function(result, callback){
console.log('n6');
if(result != 1) {
console.log('n6.1');
callback(errorCode404);
}
console.log('n6.2');
callback(null, 'Dossier mise a jour.');
}
], function(err, result){
...
});
Can someone clarify me about this?
What's happening is that the update callback has three parameters: error (if any), the count of records that were modified, and a status object. waterfall handles the error parameter, but the last two are passed as parameters to the subsequent waterfall function (n6), with the callback being provided as the third parameter, not the second.
So you need to change that part of your code to be something like:
...
function(dossiers, callback){
console.log('n5');
dossiers.update({'_id': mongodb.ObjectID(id)}, {$set:newData}, callback);
},
function(numModified, status, callback){
console.log('n6');
...

Resources