node js + async parallel + function call method not working - node.js

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);
});

Related

Using argument of function in Node's module async

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

Run n number of async function before calling another method in nodejs

I have variable number of async function to run. For two function, I can write like this:
async.parallel([
function(parallelCb) {
client.get('statuses/user_timeline', {screen_name: 'rajeevnodetest'}, function(error, tweets, response){
parallelCb(null, {error: error, tweets: tweets});
});
},
function(parallelCb) {
client.get('statuses/user_timeline', {screen_name: 'rajeev_jayaswal'}, function(error, tweets, response){
parallelCb(null, {error: error, tweets: tweets});
});
},
], function(error, results) {
// results will have the results of all 2
res.send(JSON.stringify(results));
});
How should I call variable number of function inside async.parallel ? I tried adding for loop inside async.parallel but it did not work. Any suggestion ?
I am assuming you will be reaching same api in order to retrive user tweets.
Therefore you have an array containing all tweeter handles:
var screenNames = ['rajeevnodetest', 'rajeev_jayaswal', ..., 'brandnewhandle'];
You can define a function to reach the API like this:
//Custom function to find user status list
var findStatus = function(handle, callback) {
client.get('statuses/user_timeline', {screen_name: handle}, function(error, tweets, response){
callback(null, {error: error, tweets: tweets});
});
}
Then you could use Asyn.map function in order to execute that function once for every element in your tweeter handle list like:
async.map(screenNames, findStatus, function(err, results) {
// results will have the results of all 2
res.send(JSON.stringify(results));
});
If you need to make calls to multiple API endpoints for each tweeter handle then you would need to use paralell and create an entry for each endpoint.
You can use async.times function Like this
function(parallelCb) {
async.times(50, function (n, next) {
client.get('statuses/user_timeline', {screen_name:'rajeevnodetest'},
function(error, tweets, response){
next(err, tweets);
});
}, function (error, results) {
// do something with your results
parallelCb(null, {error: error, tweets: results});
}
}
So if you want to Run n number of async function before calling another method You will have to use async.series method using async.times in it because according to async.parallel documentation it Run the tasks collection of functions in parallel, without waiting until the previous function has completed.
you should look into EventEmitter
call the emit method withing your async functions and hook all the function you want to run to that event name

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);
}
});

How to properly export/require

I'm trying to export one function this way:
exports.query = function(request){
conn.query(request, function(err, rows, fields){
if(err) console.log(err);
return rows[0].id;
});
}
and using it:
var mysql = require('./mysql');
console.log(mysql.query('SELECT * FROM tablename'));
Proceeding this way for getting a result involves undefined as output.
How do I to fix this, please?
Note that when I just type console.log(rows[0].id) instead of return rows[0].id it sends back 123.
Thanks in advance!
In your example, the output is being returned to the anonymous function of the database query instead of the caller of the module. You can use a callback to return output to the caller of the module.
exports.query = function(request, callback){
conn.query(request, function(err, rows, fields){
if (err) {
callback(err);
} else {
callback(null, rows[0].id);
}
});
}
Then call it like
var mysql = require('./mysql');
mysql.query('SELECT * FROM tablename', function(err, results){
if (err) {
console.error(err);
} else {
console.log(results);
}
});
That's a problem of synchrony.
the conn.query function returns undefined because it finish its execution before the results are fetched (like almost any i/o related operation on js/node).
One possible solution to that, is to provide a callback to your query function.
exports.query = function(request, cb){
conn.query(request, function(err, rows, fields){
// some "special" processing
cb(err, rows, fields);
});
};
If you're not familiar with async functions, take a look on some articles about that:
http://justinklemm.com/node-js-async-tutorial/
https://www.promisejs.org/

callback hell in loop of queries

i'm trying to get a list of distinct values and count of items. like this:
sheet_kinds: [
"cars" (10 items),
"computers" (23 items),
"utilities" (88 items)
],
so the query to get distinct values is ok. my code:
getValues:function(next){
Sheet.find().distinct('kind', function(err, rs){
for (var i = 0; i < rs.length; i++) {
Sheet.count({kind:rs[i]}, function(err, c){
next(null, rs); <====== THIS IS NOT GOOD
});
};
});
}
I cannot run next() inside a loop, I know. But how can I get a full list of count values and run next() only after all items back?
In this kind of scenario you'd be much better off using async
Install
npm install --save async
Require
var async = require('async');
Use
getValues:function(next){
Sheet.find().distinct('kind', function(err, rs){
async.map(rs, function (item, done) {
Sheet.count({kind:item}, done);
}, next);
});
}
Details
getValues:function(next){
Sheet.find().distinct('kind', function(err, rs){
// async.map is used to map a collection asynchronously
// the cb will be invoked once for each item in rs
async.map(rs, function (item, done) {
// the done callback needs to be invoked exactly once
// in this case, we just pass it to count, since
// the (err, count) result is exactly what we want (getting us the count)
Sheet.count({kind:item}, done);
// next is invoked with the err, if any, and
// the resulting map (an array of counts)
}, next);
});
}
Update
Addresses question in comments
getValues:function(next){
Sheet.find().distinct('kind', function(err, rs){
async.map(rs, function (item, done) {
Sheet.count({kind:item}, function (err, count) {
done(err, {kind:item,count:count});
});
}, next);
});
}

Resources