Return undefined value outside the loop - node.js

I'm using a for loop for checking the queries I've read before, and after I adding the wrong queries to a map and return the map I received 'undefined'.
I'm using async functions but it didn't help.
This is the function:
async function validateQueryResult(connection, queries) {
var result;
var alertsList = new Map();
return new Promise((resolve, reject) => {
for (query in queries) {
connection.execute({
sqlText: queries[query]["query"],
complete: function (err, stmt, rows) {
if (err) {
console.error('Failed to execute query ' + queries[query]["query"] + ' due to the following error: ' + err.message);
}
else {
rows[0].toString();
result = Object.values(rows[0]);
if (result[0] > 0) {
alertsList.set(queries[query], result[0]);
}
}
}
});
}
resolve(alertsList);
})
}
Thanks for help!

Your problem is, that connection.execute() is another async call. And your for-loop is done before any of the expected answers returns. Try it this way:
async function validateQueryResult(connection, queries) {
var result;
var alertsList = new Map();
return new Promise((resolve, reject) => {
for (query in queries) {
const result = await this.execute(query);
if (result && result[0] > 0) {
alertsList.set(queries[query], result[0]);
}
}
resolve(alertsList);
})
}
async function execute(query) {
connection.execute({
sqlText: queries[query]["query"],
complete: function (err, stmt, rows) {
if (err) {
console.error('Failed to execute query ' + queries[query]["query"] + ' due to the following error: ' + err.message);
}
else {
rows[0].toString();
return Object.values(rows[0]);
}
}
});
}

Related

wait for api response before moving next - nodejs

In my nodejs project, there's a function where I have two queries to get data from. First query is dependent on a flag, if flag is true, then I've to run that query and pass its data to second query. Otherwise I've to set some hard-coded data for second query. But it does not wait for first query response and run second query. I've added callbacks to it but nothing worked for me. Here is my code snippet;
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data
return Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
return dao.getFirstData(code , (err, results) => {
if (err) return callback(err);
if(results && results.length > 0){
return lstData = results;
}
});
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
asyncFuncs.push(callback => {
dao.thirdFunction(id, callback);
});
async.parallel(asyncFuncs, (err, results) => {
if (err) return callback(err);
let data1= results[0].amount;
let data2= results[1];
// some calculations with data1 & data2
return callback(err, finalResult);
});
}
No matter flag is true or false, getSecondData always returns data against d (hard-coded value). I am a newbie to nodejs, so please let me know what am I doing wrong.
SO I updated my code to add promise in it...here is updated code;
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data
Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
var prom = new Promise((resolve, reject) => {
dao.getFirstData(code , (err, results) => {
if (err) return callback(err);
if(results && results.length > 0){
let lstData = results;
return resolve(lstData);
}
});
});
prom.then((result) => {
return result;
});
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
asyncFuncs.push(callback => {
dao.thirdFunction(id, callback);
});
async.parallel(asyncFuncs, (err, results) => {
if (err) return callback(err);
let data1= results[0].amount;
let data2= results[1];
// some calculations with data1 & data2
return callback(err, finalResult);
});
}
But still same response. It is not waiting for promise result.
There plenty of ways to achieve this but I would prefer http://async.io/ to perform multi function operations.
By using promise you can do,
function f1(argument){
return new Promise((resolve, reject) => {
try {
data = // do your thing
resolve(data)
}
catch(err){
reject(err)
}
})
}
and then use await to achieve this
async function caller(){
await f1()
}
Few other links to help you [here][2]
[2]: https://stackoverflow.com/questions/22442321/callback-function-example/48333938#:~:text=A%20callback%20function%2C%20is%20a,or%20executed)%20inside%20the%20otherFunction.&text=Without%20thinking%20too%20much%2C%20see%20the%20following%20example.&text=Generally%2C%20JavaScript%20allows%20function%20as%20a%20parameter.
You can use async/await for asynchronous calls or you can uses promises. This will wait at the asynchronous calls and once you get the response your code will execute the dependent subsequent calls.
getData(req, callback) {
if(!req.flag){
lstData.push('d');// hardcoded data --> this might be an issue as you are already pushing data.
// these are async calls where you can ask your code to wait
return Reader.open(filename).then(reader => {
let code = reader.data;
if(!!code ){
var promise = dao.getFirstData(code , (err, results) => {
if (err) reject(err);
if(results && results.length > 0){
lstData = results;
resolve(lstData);
}
});
return promise --> you can subscribe this using then
}
});
}
else{
lstData.push('d');// hardcoded data
}
let asyncFuncs = [
(callback) => {
dao.getSecondData(lstData, (err, results) => {
if (err) return callback(err);
return callback(null, { amounts: results });
});
}
];
}
To get hands on this you can check the ways of using async/await
https://javascript.info/async-await

Node.js - Async.js map function only showing results of the first iteration?

I'm mapping an array when I finish the mapping I should return the whole array, but in my code the first element that it return.
In this function I'm using async.map to call getShippingMethods function, after getting the result I'm calling resolve function, but the problem the resolve function return just the first element of the array.
function getShippingZones() {
return new Promise((resolve, reject) => {
pool.getConnection(function (error, connection) {
if (error) reject("error in connection")
else {
connection.query("select * from shipping_zone", function (error, result, fields) {
if (error) reject(error)
else {
async.map(result, getShippingMethods, function (res) {
resolve(res)
})
}
})
}
})
})
}
function getShippingMethods(result, callback) {
pool.getConnection(function (error, connection) {
if (error) return (error)
else {
var id = result.id
var name = result.zone_name
console.log("zone name", name)
var query1 = "SELECT sm.id, method_name, rate_amount, rate_min, rate_max, delivry_min, delivry_max, shipping_zone_id, factors_id, factor_name FROM `shipping_method` sm, `factors` f where sm.shipping_zone_id = " + id + " and f.id = sm.factors_id"
var query2 = "SELECT * FROM `country` WHERE shipping_zone_id = " + id
connection.query(query1 + ";" + query2, function (error, results, fields) {
var shippingMethods = results[0].map(_getShippingMethod);
var countries = results[1].map(_getShippedCountries)
callback({ id: id, name: name, shippingMethods: shippingMethods, countries: countries });
});
}
})
}
function _getShippingMethod(result) {
return {
id: result.id,
methodName: result.method_name,
rateAmount: result.rate_amount,
rateMin: result.rate_min,
rateMax: result.rate_max,
deliveryMin: result.delivry_min,
deliveryMax: result.delivry_max,
factorName: {
id: result.factors_id,
name: result.factor_name
}
};
}
function _getShippedCountries(result) {
return {
id: result.id,
name: result.name,
countryCode: result.country_code
};
}
I think you're very nearly at the right result.. the solution should be fairly simple. The async library follows the Node.js pattern of error first callbacks, so when you're returning the result of a successful operation you need to do:
callback(null, result).
or in the case of an error being encountered:
callback(error)
Otherwise async.map thinks we've encountered an error and stops. (See async.map documentation)
In the function getShippingMethods you were calling the callback with the result as the first argument, this should be the second argument - so we don't stop the iteration.
We'll just change the getShippingMethods function like so:
function getShippingMethods(result, callback) {
pool.getConnection(function (error, connection) {
if (error) return (error)
else {
var id = result.id
var name = result.zone_name
console.log("zone name", name)
var query1 = "SELECT sm.id, method_name, rate_amount, rate_min, rate_max, delivry_min, delivry_max, shipping_zone_id, factors_id, factor_name FROM `shipping_method` sm, `factors` f where sm.shipping_zone_id = " + id + " and f.id = sm.factors_id"
var query2 = "SELECT * FROM `country` WHERE shipping_zone_id = " + id
connection.query(query1 + ";" + query2, function (error, results, fields) {
if (error) {
// Our query failed, so we pass error as the first argument to the callback.
callback(error)
} else {
var shippingMethods = results[0].map(_getShippingMethod);
var countries = results[1].map(_getShippedCountries)
// This is an error first callback, so pass null here since our query was successful
callback(null, { id: id, name: name, shippingMethods: shippingMethods, countries: countries });
}
});
}
})
}
And we need to change getShippingZones like so:
function getShippingZones() {
return new Promise((resolve, reject) => {
pool.getConnection(function (error, connection) {
if (error) reject("error in connection")
else {
connection.query("select * from shipping_zone", function (error, result, fields) {
if (error) reject(error)
else {
// Change to an error first callback.
async.map(result, getShippingMethods, function (err, res) {
if (err) {
reject(err);
} else {
resolve(res);
}
})
}
})
}
})
})
}

Returning an array from function in nodejs

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

Do something async with underscore map

function addSomething(data) {
var defer = q.defer();
data = _.map(data, function(item) {
item['something'] = callSomethingAsync();
return item;
});
return defer.promise;
}
How can I handle this problem. The only way I found is using Async.js.
But maybe there is a better way using $q?
EDIT:
function getScopes(item) {
var defer = q.defer();
var query = "SELECT somevalue FROM Something WHERE ID = '" + item.id + "'";
mysql.query(query, function(err, data) {
if (err) {
defer.reject(err);
} else {
item[newkey] = data
defer.resolve(item);
}
});
defer.resolve(data)
return defer.promise;
}
//add necessary scopes to the audit
function addScopes(data) {
var promises = _.map(data, function(item) {
return getScopes(item);
});
return Promise.all(promises);
}
How I can prevent using defer in the getScopes function?
Edit 2:
var query = "SELECT * FROM tiscope";
Q.nfcall(mysql.query, query).then(function(data) {
console.log(data);
});
there is nothing returned.
Here is how I use mysql:
var sql = require('mysql');
var connection = sql.createConnection({
host : 'xxx',
user : 'xxx',
password : 'xxx',
database : 'xxx'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
} else {
console.log('mysql connection established');
}
});
module.exports = connection;
Maybe there is the mistake.
A lot of promise libraries provide a map function. Seems Q does not. No matter the the same can be accomplished with vanilla promises (and Q) anyway using the all function.
First things first. Avoid defer. It makes code more difficult to reason and maintain. There are only a few rare cases when defer is needed. The rest of the time a normal promise constructor/helper functions will work better.
Normal Promises Example
function addSomething() {
var promises = _.map(data, function(item) {
return callSomethingAsync(item);
});
return Promise.all(promises);
}
Q Promises Example
function addSomething() {
var promises = _.map(data, function(item) {
return callSomethingAsync(item);
});
return $q.all(promises);
}
Presumably callSomethingAsync returns a promise. If not use the promise constructor pattern:
function toPromise(asyncFn, args) {
return new Promise(function (resolve, reject) {
function callback(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
}
asyncFn(callback, args);
});
}
function addSomething() {
var promises = _.map(data, function(item) {
return toPromise(callSomethingAsync, item);
});
return Promise.all(promises);
}

Promise.all().then() - then() executes before all() completed

In a gulp task I have the following code that creates an array of gitAction promises that get executed within a Promise.all() statement. Afterwards, I'm calling a further statement in a then(). But the then() is being called before the git pulls in the all() have terminated. Any clues please?
var git = require('gulp-git');
var gitActionPromise = function(repo, url) {
console.log('git action '+repo);
var pathToRepo = './repos/'+repo;
if (fs.lstatSync(pathToRepo).isDirectory()) {
return new Promise((resolve, reject) => {
git.pull('origin', 'master', {cwd: pathToRepo}, function (err) {
console.log(repo + " pull done!");
if (err) {
console.log('error');
reject(err);
} else {
console.log('ok');
resolve();
}
})
})
} else {
return new Promise((resolve, reject) => {
git.clone(url, {cwd: pathToRepo}, function (err) {
console.log(repo + " clone done!");
if (err) {
console.log('error');
reject(err);
} else {
console.log('ok');
resolve();
}
})
})
}
};
var repos = package.repos || {};
var promises = Object.keys(repos).map(function(repo) {
return gitActionPromise(repo, repos[repo]);
});
Promise.all(promises).then(
console.log('something else') <= this line was causing my issue
); needed to be enclosed in function
You have to pass a function to then:
Promise.all(promises).then(function() {
console.log('something else');
});
The code you have simply logs "something else" right away.

Resources