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
});
Related
Hello I am having an issue with the following sequence, I need to run multiple queries which build on each other that are in a for loop then once the final result is obtained to implement the result. I am having an issue where my for loop is looping past the query, also I need to stop the code while the findX function is running.
I know this is an async problem but I don't see how I could chain promises, or use the async npm package with needing to loop queries that depend on the result of the previous query. Thanks in advance.
function findX(){
//executes another query
}
function solve(res, connection, info, requestArr, callback){
var parentID = null;
var obj = {};
for (var i = 0; i <= requestArr.length; i++) {
connection.query("SELECT WHERE ", [parentID, requestArr[i]], function(err, results) {
if(results[0]['x']){
var obj = findX(x)
break;
}else{
parentID = results[0]['parentID'];
}
});
}
//Do stuff with obj only after the final result has been set in the for loop
}
You can use Async TimesSeries.
// Pretend this is some complicated async factory
var createUser = function(id, callback) {
callback(null, {
id: 'user' + id
});
};
// generate 5 users
async.times(5, function(n, next) {
createUser(n, function(err, user) {
next(err, user);
});
}, function(err, users) {
// we should now have 5 users
});
So, in your example would be something like this:
var iterations = requestArr.length - 1,
parentID,
obj;
var getResults = function (i, callback) {
connection.query("SELECT WHERE ", [parentID, requestArr[i]], function (err, results) {
if (results[0]['x']) {
obj = findX(x);
callback('done');
}
else {
parentID = results[0]['parentID'];
callback();
}
});
};
async.timesSeries(iterations, function (n, next) {
getResults(n, function (err) {
next(err);
});
}, function (err) {
// use obj
});
This is my code:
var shopId=[1,2,3,4];
async.each(shopId,function (item,callback) {
model.client.query("SELECT categoryId shopId=? ", [shopId], function (err, rows) {
if (rows.length > 0) {
var asyncData = rows;
//categoryId will be in the format [1,2,3,4]
async.each(asyncData,function (item, callback) {
var categoryId = item.categoryId;
async.series([
function (callback) {
model.client.query("select categoryName from category where categoryId = ?", [categoryId], function (err, data) {
callback(null, data);
});
}],
function (err, results) {
item.category = results[0];
callback();
});
},function (err) {
callback(asyncData); //getting data here
});
}
});
},function (err,result) {
res.json(result); //not getting data here
});
I am new to aysnc methods. I am not able to pass the result to final function.
Supposing that there is a shop table, you can join your tables to save a query.
const sql = 'select categoryName from category as c inner join shop as s on c.categoryId = s.categoryId where s.shopId = ?'
then
const shopId = [1, 2, 3, 4];
const finalResult = [];
async.each(shopId, function(item, callback) {
model.client.query(sql, [shopId], function (err, rows) {
// do not forget error handling !
if (rows.length > 0) {
finalResult.push(rows);
return callback();
}
return callback(); // do not forget to return callback in every case
});
}, function(err) { // in async each callback, you only get errors
if (err)
return res.json(err); // or whatever error handling
res.json(finalResult);
});
Also, considering your code, I would advise to name differently your callbacks to avoid errors or forgets. i.e.
async.each([], function(item, cbkGlobal) {
async.each([], function(item, cbkEach) {});
});
And async.series is usefull when you want multiple functions to get execute in order. But here you are executing only one function...
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);
}
Hi I have this code but when finish the result is not the espected because didn't run in the sequence that I wish
here is the code:
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
var req_games = [];
if (!err) {
for (var i in games) {
req_games.push(games[i]);
models.users.findOne({_id: games[i].w_id}, function (err, user) {
req_games[i].w_id = user.user;
console.log(req_games[i].w_id) //< -- 3
});
console.log('a ' + req_games[i].w_id) //<-- 2
}
user_data.games = req_games; // <-- 1
}
});
at the end of the task req_games didnt have any update because it's running in the sequence that I put in the comments in the code
This may help you using Q(promises)
obj.find = function(model, condition) { //make your find to return promise
var deferred = q.defer();
model.find(condition, function(err, results) {
if (err) {
logger.log(err);
deferred.reject(err);
} else {
deferred.resolve(results);
}
});
return deferred.promise;
}
ArraysOfId.forEach(function (id) {
var tempProm = mongoUtilsMethodObj.find(schemaObj.Asset, id).then(function (assetObj) {
---- your code
return q.resolve();
});
promArr.push(tempProm);//push all promise to array
});
q.all(promArr).then(function () {
// this will be called when all promise in array will we resolved
})
Here is a version using the async library to map your game values.
var async = require('async');
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
if(err) {
// or whatever your error response happens to be
return res.render('user.swig', {error: err});
}
async.map(games, function(game, nextGame) {
models.users.findOne({_id: game.w_id}, function (err, user) {
game.w_id = user.user;
nextGame(err, game);
});
}, function(err, req_games) {
user_data.games = req_games;
res.render('user.swig', {user: user_data});
});
});
exports.getCityCascade = function (req, res) {
var result = {};
Province.find().exec(function (err, provinces) {
result.provinces = provinces;
var provinceCount = 0;
async.whilst(
function () {
return provinceCount < provinces.length
}
, function (callback) {
City.find({province: provinces[provinceCount].id}).exec(function (err, cities) {
if (err) {
callback(err);
} else {
result.provinces[provinceCount].cities =cities;
}
provinceCount++;
callback(null , result);
});
}, function (err, result) {
if (err) return res.jsonp({message: err.message});
return res.jsonp({
status: '200',
results: result});
}
)
})
}
When I add the cities field to provinces, It seems doesn't work. the response body doesn't contain the filed cities. How to fix it? Any advice would be very helpful.
The problem is just a conflict between variable names: you declared a var result outside Province.find(), but the async.whilst() also uses result as the second argument of its callback function. Just rename one of them and it should work.