I'm having trouble with setting a variable or at least returning it in async waterfall. I know that you can't return in async but I did a callback on my variable, jsonFinal and it goes into the function below under data.
function getIndividualMatchJSONObjHelper(matchData, matchParticipantData, indexIter) {
var individualMatchURL = 'https://na1.api.riotgames.com/lol/match/v3/matches/' + matchData.matchID[indexIter] + '?api_key=' + API_KEY;
var jsonFinal;
async.waterfall([
function(callback) {
request(individualMatchURL, function(err, response, body) {
if(!err && response.statusCode == 200) {
var json = JSON.parse(body);
for (var j = 0; j < 10; j++) {
if (matchData.championID[indexIter] == json['participants'][j].championId) {
jsonFinal = json['participants'][j];
callback(null, jsonFinal);
}
}
}
else {
console.log(err);
}
});
}
],
function(err, data) {
if(err) {
console.log(err);
}
else {
jsonFinal = data;
}
});
console.log(jsonFinal);
return jsonFinal;
}
How can I get the function to return jsonFinal properly?
You can only get the variable within the callback like with any asynchronous operation. Therefore, modify your function to also accept a callback.
function getIndividualMatchJSONObjHelper(matchData, matchParticipantData, indexIter, callback) {
var individualMatchURL = 'https://na1.api.riotgames.com/lol/match/v3/matches/' + matchData.matchID[indexIter] + '?api_key=' + API_KEY;
async.waterfall([
function (callback) {
request(individualMatchURL, function (err, response, body) {
// always trigger the callback even when you have errors or else your program will hang
if (err)
return callback(err);
if (response.statusCode != 200)
return callback(new Error('Status code was ' + response.statusCode));
var json = JSON.parse(body);
for (var j = 0; j < 10; j++) {
if (matchData.championID[indexIter] == json['participants'][j].championId) {
// match found: send back data
console.log('inside', json['participants'][j]);
return callback(null, json['participants'][j]);
}
}
// if it reaches this point, no match was found
callback();
});
}
], callback); // note: this outer 'callback' is NOT the same as the inner 'callback'
}
Then when you call your function e.g.
getIndividualMatchJSONObjHelper(data, participants, indexIter, function (err, json) {
// you can only get the JSON at this point
console.log('outside', json);
matchParticipantData.specificParticipantData[i] = json;
});
Related
I have these 2 functions
Here I get details from sales table
var getLedgerDetails = function (name, id, res) {
var response = [];
var f = '%d %b %Y';
connection.query("SELECT id,voucher_type,DATE_FORMAT(date,?) as date,amount,voucher_number FROM sales WHERE ledger_name=? and company_id=?", [f, name, id], function (err, result) {
if (err) {
console.log(err)
}
else {
if (result.length > 0) {
var r = JSON.stringify(result, null, 2);
var row = JSON.parse(r);
return row[0];
}
else {
}
}
})
};
and second is
here i want to access the getLedgerDetails Function
getDetails=function(name,id,res){
//**returns undefined**
console.log(getLedgerDetails(name,id,res));
}
but it returns me undefined..It makes the function call but returns no value
where i am wrong??
Its because your code is asynchronous, you have to return your data in a callback function which will be called only at the end.
You can try something like this :
var getLedgerDetails=function(name,id,res, callback) {
var response = [];
var f = '%d %b %Y';
connection.query("SELECT id,voucher_type,DATE_FORMAT(date,?) as date,amount,voucher_number FROM sales WHERE ledger_name=? and company_id=?", [f, name, id], function (err, result) {
if (err) {
callback(err, null);
}
else {
if (result.length > 0) {
var r = JSON.stringify(result, null, 2);
var row = JSON.parse(r);
callback(null, row[0]);
}
else {
callback(null, null);
}
}
});
};
And your getDetails function
getDetails=function(name,id,res){
getLedgerDetails(name, id, res, function(err, row) {
if (err) {
console.log(err);
}
else {
console.log(row);
}
});
};
It seems you want your function getLedgerDetails to return data whereas the anonymous function associated with your connection.query function is actually returning your data. Being the asynchronous nature of javascript
In your case, you can you can use Promises.
Well, Promises provide us with a cleaner code and handling errors with promises is very easy. Also, promises are better when comes to handling nested callbacks that is one after the another.
For Promise:
var Promise = require('promise');
var getLedgerDetails=function(name,id,res) {
return new Promise(function (resolve, reject) {
var response=[];
var f='%d %b %Y';
connection.query("SELECT id,voucher_type,DATE_FORMAT(date,?)
as date,amount,voucher_number FROM sales WHERE
ledger_name=? and
company_id=? ,[f,name,id],function(err,result){
if(err){
reject(err);//or any custom error message.
}else {
if(result.length>0){
var r=JSON.stringify(result,null,2);
var row=JSON.parse(r);
resolve(row[0]);
}else{
}
}
});
}
}
Usage:
getLedgerDetails.then(function(success){
console.log(success)// your db data.
}).catch(function(error) {
// error handle
});
Right now I have a piece of code which makes two http requests in parallel.
var request = require('request');
var async = require('async');
var fs = require('fs');
module.exports = {
req : function(options) {
//populate list with 2 lookups
var lookup_list = [];
for (var i = 0; i < 2; i++) {
if(i == 1) {
options.timeout = 200;
}
lookup_list.push(options);
}
//iterate through list with and do request calls
async.map(lookup_list, function(options, next) {
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var body = JSON.parse(body);
next(null, body);
} else {
next(error || response.statusCode);
}
});
//after both requests are finished, deal with responses
}, function(err, results) {
if (!err) {
console.log(results);
/*
fs.appendFile('log.txt', JSON.stringify(results[1]) + "\n",function callback(error){
if (error) {
return console.error('write failed: ', error);
}
});
*/
} else {
console.error('request failed: ', err);
}
});
}
}
I want a to return the array results from the async.map callback when parallel.req() is called.
I've tried to provide a callback for req() and have it be called in the callback for async.map but no luck. I also tried other returns and callbacks elsewhere but have had no success. I would like some guidance to resolve this issue.
Just started working with Nodejs and facing this issue while pushing the array as a response in the below code. I know this is happening because of the asynchronous nature of Nodejs, tried to apply async as well but did not get the desired result. Could someone let me know the fix of this code:
array = [];
var company = companySchema.Company;
company.findOne({_id: companySchema.objectId(req.tempStore.companyId)}, function (err, comp) {
if (err) {
console.log(err);
}
else {
var i;
var length = comp.events.length;
var dataset = datasetSchema.dataset;
for (i = 0; i < length; i++) {
dataset.find({companyId:comp.events[i]}, function (err,data) {
if (err) {
console.log(err);
}
else {
array.push(data);
}
console.log("array-----"+array); // prints array here
});
}
}
console.log("array-----"+array); // array is empty hence causing empty response
res.response.data = array;
next();
});
You can use mongoDB $in clause for this task:
var company = companySchema.Company;
company.findOne({_id: companySchema.objectId(req.tempStore.companyId)}, function (err, comp) {
if (err) {
console.log(err);
} else {
var dataset = datasetSchema.dataset;
dataset.find({companyId : {$in : comp.events}}, function (err, docs) {
if (err) {
console.log(err);
} else {
console.log("array: " + docs); // prints array here
res.response.data = docs;
next();
}
});
}
});
I would like to do something like this
function scan(apath){
var files = fs.readdirSync(apath);
for(var i=0; i<files.length;i++){
var stats = fs.statSync(path.join(apath,files[i]))
if(stats.isDirectory()){
results.push(path.join(apath, files[i]))
scan(path.join(apath,files[i]))
}
if(stats.isFile()){
results.push(path.join(apath,files[i]))
}
}
}
but asynchronously.
Trying this with asynchronous functions led me to a nightmare with something like this.
function scan(apath){
fs.readdir(apath, function(err, files)){
var counter = files.length;
files.forEach(function(file){
var newpath = path.join(apath, file)
fs.stat(newpath, function(err, stat){
if(err) return callback(err)
if(stat.isFile())
results.push(newpath)
if(stat.isDirectory()){
results.push(newpath)
scan(newpath)
}
if(--counter <=0) return
})
})
}
}
All hell breaks loose in node's stack because things don't happen in logical succession as they do in synchronous methods.
you can try async module, and use like this:
function scan(apath, callback) {
fs.readdir(apath, function(err, files) {
var counter = 0;
async.whilst(
function() {
return counter < files.length;
},
function(cb) {
var file = files[counter++];
var newpath = path.join(apath, file);
fs.stat(newpath, function(err, stat) {
if (err) return cb(err);
if (stat.isFile()) {
results.push(newpath);
cb(); // asynchronously call the loop
}
if (stat.isDirectory()) {
results.push(newpath);
scan(newpath, cb); // recursion loop
}
});
},
function(err) {
callback(err); // loop over, come out
}
);
});
}
look for more about async.whilst
function getUsernameAssociatedWithToken (token) {
console.log('\n\t\tgetUsernameAssociatedWithToken');
console.log("\t\t"+token);
var userReturn = "";
queryAsync(returnVal);
function queryAsync(callback){
connection.query("SELECT * FROM users WHERE token = '"+token+"'", function (error, results, fields) {
if (error) {
console.log(error);
callback(null);
}
if (results.length > 0) {
userReturn = results[0].user;
callback(userReturn);
} else {
callback(null);
}
});
};
function returnVal(str){
userReturn = str;
console.log('vaaaaal');
console.log(userReturn);
}
return userReturn;
}
the last "return" is called before the query function is executed (its not supposed to). How would I do this using callbacks?
I've tried this but this also failed:
function getUsernameAssociatedWithToken (token) {
console.log('\n\t\tgetUsernameAssociatedWithToken');
console.log("\t\t"+token);
var userReturn = "";
function queryAsync(){
connection.query("SELECT * FROM users WHERE token = '"+token+"'", function (error, results, fields) {
if (error) {
console.log(error);
return null;
}
if (results.length > 0) {
userReturn = results[0].user;
return userReturn;
} else {
return null;
}
});
};
return (queryAsync());
}
You can't directly return the result of an asynchronous call from a function because (as you've seen) the function returns before the asynchronous call completes. Instead, your function has to support a callback parameter that it will call to deliver the result back to the caller when the asynchronous call completes.
function getUsernameAssociatedWithToken (token, callback) {
...
queryAsync(callback);
}