Async.waterfall function gets called twice - javascript

I have an async waterfall Array where the function otherIngrLists() is the 3rd to be executed. Every function before that worked fine.
function otherIngrLists(userslist, callback){
collection = db.get('ingrList');
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
console.log(otherListsCount);
callback(null, otherLists, otherListsCount, userslist);
} else {
callback(err, null);
}
});
},
The Problem is that this function is called twice. I assured this with a simple console.log().
How did I manage to call this function again? Did I get the concept of callbacks wrong as I use them to be passed on to the next function?
Also after this function executing twice an error ist thrown. It has nothing to to with this problem though and I will concern my self with that later.
Thank you for your time!
Waterfall Array in router.get:
router.get('/:userid', function(req, res) {
var db = req.db;
var collection;
var userid = req.params.userid;
async.waterfall(
[
function getIngrList(callback, userid) {
var route = 'http://localhost:3000/users/zutatenliste/'+userid;
request(route, function(err, response, body){
if (!err && response.statusCode === 200) {
var userlist = body;
callback(null, userlist);
} else {
callback(err, null);
return;
}
});
},
function otherIngrLists(userlist, callback){
collection = db.get('zutatenListe');
console.log(userid);
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
callback(null, otherLists, otherListsCount, userlist);
} else {
callback(err, null);
}
});
},
function pushInArray(otherLists, otherListsCount, userlist, callback){
console.log("test");
...
...}
}
}
Edit 1: --Also either if cases are executed, first the true one then the false--
// Does not happen anymore
Edit 2: Added the whole Thing until the problematic function

Please provide some Additional details as this function seems perfect and No, You haven't misunderstood the concept of callback you are using it correctly.
Structure of Async Waterfall
var create = function (req, res) {
async.waterfall([
_function1(req),
_function2,
_function3
], function (error, success) {
if (error) { alert('Something is wrong!'); }
return alert('Done!');
});
};
function _function1 (req) {
return function (callback) {
var something = req.body;
callback (null, something);
}
}
function _function2 (something, callback) {
return function (callback) {
var somethingelse = function () { // do something here };
callback (err, somethingelse);
}
}
function _function3 (something, callback) {
return function (callback) {
var somethingmore = function () { // do something here };
callback (err, somethingmore);
}
}
so, in waterfall you can pass the values to the next function and your 3rd function is correct.
Edited
async.waterfall(
[
//can not give userId as second parameter
function getIngrList(callback) {
//if you want userId you can pass as I shown above or directly use here if it's accessible
var route = 'http://localhost:3000/users/zutatenliste/'+userid;
request(route, function(err, response, body){
if (!err && response.statusCode === 200) {
var userlist = body;
callback(null, userlist);
} else {
callback(err, null);
// return; no need
}
});
},
function otherIngrLists(userlist, callback){
collection = db.get('zutatenListe');
console.log(userid);
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
callback(null, otherLists, otherListsCount, userlist);
} else {
callback(err, null);
}
});
},
function pushInArray(otherLists, otherListsCount, userlist, callback){
console.log("test");
...
...}
As said you can not pass userId as last parameter over there. Let me know if you still get the same error.

First you need to declare you function:
function myFuntion(userId, callback) {
async.waterfall([
function(callback) {
//do some thing here
callback(null, userlist);
}, function(userId, callback) {
//do something here
callback(null, orderList, orderListCount, userlist);
}
], function(err, orderList, orderListCount, userlist) {
if(err)
console.log(err);
else
callback(orderList, orderList, userlist);
})
}
After that you can use function:
myFuntion(userId, function(orderList, orderListCount, userlist) {
console.log(orderList);
console.log(orderListCount);
console.log(userlist);
})

Related

Run loop on the server with node.js

Let's say i need to constantly collecting some data from a lot of clients and in parallel running some complex loop that solving some stuff with this data. How can i do it? Should i just write this in my piece of code:
app.get('/', function(req, res) {
res.sendFile(__dirname + '/public/views/index0.html');
});
io.sockets.on('connection', function(socket) {
// SOME STUFF WITH THE SOCKET
socket.on('disconnect', function(data) {
//SOME OTHER STUFF
});
});
while(...) {
//THE LOOP STUFF
}
Or i need to use the setTimeout() and setInterval() functions? How can i do the loop on the server that runs in parallel with the callbacks' stuff?
Don’t use while for make it, this block a thread. setTimeout() will run only once. You need to use setInterval() function.
You can use the async module to handle the async operation with the callback or use promise to avoid callback.
Here how I handle a complex async for each operation, that might helpfull to you get idea handeling ayncs forach
var cond = { _schedule: schedule_id }; // find curse by schedule id
Course.find(cond, function (err, courses) {
if (err) {
callback({ "success": false, "message": "Not able to update" });
} else {
async.forEachLimit(courses, 1, function (course, coursesCallback) {
async.waterfall([
function (callback) {
var schedule_date = moment(change_data.date).format('YYYY-MM-DD') + "T00:00:00.000Z"
var Assignmentcond = {
assignment_schedule_order: {
$gte: schedule_date
},
_course: course._id,
_schedule: schedule_id,
_user: userid
};
Assignment.find(Assignmentcond)
.populate({
path: '_course',
})
.lean()
.sort({ assignment_schedule_order: 1 })
.exec(function (err, AssignmentList) {
if (err) {
callback(null, '');
} else {
//console.log("------------------AssignmentList---------------------------");
//console.log(AssignmentList);
async.forEachLimit(AssignmentList, 1, function (ThisAssignmentCell, ThisAssignmentCellCallback) {
async.waterfall([
function (callback) {
var SearchObj = items;
var lebelObject = {};
for (var i = 0, flag = 0, insert = 0; i < SearchObj.length; i++) {
if (SearchObj[i].date == ThisAssignmentCell.assignment_schedule_date) {
flag = 1;
}
if (flag == 1 && SearchObj[i].label != "") {
if (ThisAssignmentCell.day == SearchObj[i].day_index) {
insert = 1;
var lebelObject = SearchObj[i];
break;
}
}
}
callback(null, ThisAssignmentCell, lebelObject, insert);
},
function (ThisAssignmentCell, SearchObj, insert, callback) {
console.log('----------------------');
console.log('ThisAssignmentCell', ThisAssignmentCell);
console.log('SearchObj', SearchObj);
console.log('----------------------');
if (insert > 0) {
var query = { _id: ThisAssignmentCell._id },
fields = {
assignment_date: moment(SearchObj.date).format('MM/DD/YYYY'),
assignment_schedule_date: moment(SearchObj.date).format('YYYY-MM-DD'),
assignment_schedule_order: new Date(SearchObj.date),
day: SearchObj.day_index,
dayNum: SearchObj.weekday_num
},
options = { upsert: false };
Assignment.update(query, fields, options, function (err, affected) {
callback(null, '');
});
} else {
// var cond = { _id: ThisAssignmentCell._id};
// Assignment.remove(cond)
// .exec(function (err, cnt) {
// callback(null, '');
// });
}
}
], function (err, result) {
// result now equals 'done'
console.log('done')
ThisAssignmentCellCallback();
});
}, function (err) {
console.log("Assignment For Loop Completed");
callback(null, AssignmentList);
});
}
});
}
], function (err, result) {
// result now equals 'done'
console.log('done')
coursesCallback();
});
}, function (err) {
console.log("courses For Loop Completed");
});
}
});

Make multiple callbacks from node js asynchronous function

How can I return a object of data returned by asynchronous function called multiple times from within a asynchronous function.
I'm trying to implement like this :
var figlet = require('figlet');
function art(dataToArt, callback)
{
var arry[];
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[0] = data;
callback(arry);
});
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[1] = data;
callback(arry);
});
}
art('Hello World', function (data){
console.log(data);
});
How can I do it correctly, I searched and searched but couldn't find a solution.
Ps. I'm using Figlet.js
I don't know if you're ok using an external module, but you can use tiptoe.
Install it using npm install tiptoe like any regular module and it basically goes like this:
var tiptoe = require('tiptoe')
function someAsyncFunction(obj, callback) {
// something something
callback(null, processedData);
}
tiptoe(
function() {
var self = this;
var arr = ['there', 'are', 'some', 'items', 'here'];
arr.forEach(function(item) {
someAsyncFunction(item, self.parallel());
});
},
function() {
var data = Array.prototype.slice.call(arguments);
doSomethingWithData(data, this);
},
function(err) {
if (err) throw (err);
console.log('all done.');
}
);
the someAsyncFunction() is the async function you want to call does something and calls the callback parameter as a function with the parameters error and data. The data parameter will get passed as an array item to the following function on the tiptoe flow.
Did it Myself :) Thanks to mostafa-samir's post
var figlet = require('figlet');
function WaterfallOver(list, iterator, callback) {
var nextItemIndex = 1;
function report() {
nextItemIndex++;
if(nextItemIndex === list.length)
callback();
else
iterator([list[0],list[nextItemIndex]], report);
}
iterator([list[0],list[1]], report);
}
var FinalResult = [];
WaterfallOver(["hello","Standard","Ghost"], function(path, report) {
figlet.text(path[0], { font: path[1] }, function(err, data) {
if (err) {
FinalResult.push("Font name error try help");
report();
return;
}
data = '<pre>.\n' + data + '</pre>';
FinalResult.push(data);
report();
});
}, function() {
console.log(FinalResult[0]);
console.log(FinalResult[1]);
});

Callback is not a function in mongoose.find({})

I am new to Node.js and mongoose, i am trying to query objects from a mongo collection using find({}) and the function is as follows :
schema.statics.listAllQuizes = function listAllQuizes(){
Model.find({},function(err,quizes,cb){
if(err){
return cb(err);
}else if(!quizes){
return cb();
}
else {
return cb(err,quizes);
}
});};
But when i call this function i get an error saying
return cb(err,quizes);
^
TypeError: cb is not a function
I am stuck at this point, can someone please help me with this, thanks in advance.
The callback should an argument to listAllQuizes, not an argument to the anonymous handler function.
In other words:
schema.statics.listAllQuizes = function listAllQuizes(cb) {
Model.find({}, function(err, quizes) {
if (err) {
return cb(err);
} else if (! quizes) {
return cb();
} else {
return cb(err, quizes);
}
});
};
Which, logically, is almost the same as this:
schema.statics.listAllQuizes = function listAllQuizes(cb) {
Model.find({}, cb);
};
Here's an example on how to use it:
var quiz = App.model('quiz');
function home(req, res) {
quiz.listAllQuizes(function(err, quizes) {
if (err) return res.sendStatus(500);
for (var i = 0; i < quizes.length; i++) {
console.log(quizes[i].quizName)
}
res.render('quiz', { quizList : quizes });
});
}
Assuming you have code somewhere that looks like this:
foo.listAllQuizzes(function (err, quizzes) {
...
});
Then your function listAllQuizzes is passed a callback:
schema.statics.listAllQuizzes = function (cb) {
Model.find({}, function(err, quizzes) {
if (err) return cb(err);
cb(null, quizzes);
});
};

What is wrong with my async.series

I am trying to execute an async series in nodejs with https://github.com/caolan/async#series :
async.series([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
function getLightsState(ids, callback) {
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
callback(null, lightsState);
}
], function (err, result) {
console.log(result);
});
but its returning me this error :
callback(null, lightsState); TypeError : undefined is not a function.
I dont understand why..
How do i pass my object lightsState to my other function ?
You won't get ids in your second task, but you'll get a callback as is described in docs.
You could do:
async.series([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
], function (err, result) {
var ids = result[0]
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
});
But this goes against the conventional use-case of async.series, you only have one async task there.
What you're after for is probably async.waterfall - so here's how that would look like:
async.waterfall([
function getLightsId(callback) {
args = {
path: {
"username": "username"
}
};
client.registerMethod("getLightState", "http://bridgeip/api/${username}/lights/", "GET");
client.methods.getLightState(args, function (data, response) {
var ids = [];
for (key in data) {
ids.push(key);
}
callback(null, ids);
});
},
function getLightsState(ids, callback) {
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
}, function(err) {
callback(err, lightsState)
});
}
], function (err, result) {
console.log(result);
});
Oh, and I thought that async.each needed a callback. I'm not sure, maybe it was you intention not to be so?
its returning me this error: callback(null, lightsState); TypeError : undefined is not a function.
Because callback is not a function. Only the first argument that is passed to your function getLightsState(ids, callback) { is one. Check the docs for series:
tasks - An array or object containing functions to run, each function is passed a
callback(err, result)
series(tasks) runs the functions in the tasks array in series, each one running once the previous function has completed.
In contrast, these are the docs for the waterfall function - which is what you want:
Runs the tasks array of functions in series, each passing their results to the next in the array.
Btw,
var lightsState = new Object();
async.each(ids, function (id) {
getLightState(id, function (state) {
lightsState[id] = state;
});
});
callback(null, lightsState);
is unlikely to work, you probably want to use reduce instead:
async.reduce(ids, {}, function(lightsState, id, rcallback) {
getLightState(id, function(state) {
lightsState[id] = state;
rcallback(null, lightsState);
});
}, callback);

Async.js waterfall (functions defined outside of the array)

I am using async.js for the first time and would like to seperate out the function array into seperate functions. I have:
working code
async.waterfall([
function(callback)
{
var querySuccess = function (tx, result)
{
callback(null, result.rows.item(0).EventImportTime || "");
};
var queryError = function (tx, e)
{
callback("Query Error")
};
database.open();
database.query("SELECT EventImportTime FROM Contact WHERE Contact.Id = ?", [contactId], querySuccess, queryError);
},
function(lastImportTime, callback)
{
var url = "";
url += 'MobileGetvents.aspx?';
url += '&LastImportTime=';
url += lastImportTime;
url += '&Format=JSON';
callback(null, url)
},
],
function(err, result)
{
if (err)
console.log("Error Happened");
else
{
console.log(result);
getJSON(result, callback,
errorCallback)
}
})
I want
async.waterfall([
getLastImportTime(callback) ,
buildUrl(lastImportTime, callback),
],
//callback
);
However when I run this code it always returns
Uncaught ReferenceError: lastImportTime is not defined
I would assume that you want this instead:
var getLastImportTime = function(callback) { };
var buildUrl = function(lastImportTime, callback) { };
async.waterfall([
getLastImportTime,
buildUrl,
],
//callback
);

Categories