Problem with query in foreach loop in node js - mysql

I am fetching results from a query and want to pass value from result on the next query. Here is my code. But it's not working, I tried setTimeOut function as well.
dbcon.query('SELECT ci_offers.*, ci_advertisers.id as merchant_id, ci_advertisers.full_name, ci_advertisers.phone, ci_advertisers.companylogo FROM ci_offers, ci_advertisers WHERE ci_offers.advertiser_id = ci_advertisers.id AND ci_offers.is_active=1', function(error, results, fields) {
if (error) throw error;
if (results.length > 0) {
var objectOffer;
var objCoin;
// async.forEachOf(results, function (dataElement, i, inner_callback){
results.forEach((val) => {
objectOffer = jsonParser(val);
var token_id = objectOffer.token_id;
var redeem_coin_grabbed = 0;
if (token_id > 0) {
dbcon.query('SELECT count(id) as coingrabbed FROM ci_grabcoin_details_for_game WHERE user_id = ? AND coin_id= 33', [user_id, token_id], function(error1, results1, fields1) {
if (error1) throw error1;
});
}
val["coingrabbed"] = redeem_coin_grabbed;
final.push(val);
});
}
res.send(final);
});

Please check if this works, Using this idea https://stackoverflow.com/a/7053992/9216722
let final = [];
dbcon.query('SELECT ci_offers.*, ci_advertisers.id as merchant_id, ci_advertisers.full_name, ci_advertisers.phone, ci_advertisers.companylogo FROM ci_offers, ci_advertisers WHERE ci_offers.advertiser_id = ci_advertisers.id AND ci_offers.is_active=1', function(error, results, fields) {
if (error) throw error;
if (results.length > 0) {
var objectOffer;
var objCoin;
// async.forEachOf(results, function (dataElement, i, inner_callback){
let done = false;
let count = 0;
const markDone = (err) => {
count++;
if ( !done && results.length === count) {
done = true;
res.send(final);
}
};
results.forEach((val) => {
objectOffer = jsonParser(val);
var token_id = objectOffer.token_id;
var redeem_coin_grabbed = 0;
if (token_id > 0) {
dbcon.query('SELECT count(id) as coingrabbed FROM ci_grabcoin_details_for_game WHERE user_id = ? AND coin_id= 33', [user_id, token_id], function(error1, results1, fields1) {
if (error1) throw error1;
});
}
val["coingrabbed"] = redeem_coin_grabbed;
final.push(val);
markDone();
});
}
});

Related

variable value becomes undefined in NodeJS ExpressJS

I am working with NodeJS using ExpressJS framework in a mysql backend. I am running a query inside a for loop and my loop and work afterwards depends on the return value of the query. I am not very good with mysql query so I am running it through a for loop.
The problem is, due asynchronous [I guess!], the for loop ends long before the query result comes out.
Here is my code:
function search_people_step2(user_id, search_criteria, user_friend)
{
var first_name_friends = [];
var last_name_friends = [];
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
}
});
}
Now,I can get the value (using console.log) inside the query statement, however, on the outside, the value becomes empty (undefined) since the rest of the code has already been computed.
How can I solve this?
Thanks in advance.
The first thing that I find weird in your code is that you are not using an IN statement in your SQL query (not directly related to your problem though) which means you are making as many requests as there are entries in user_friend. The problem is that the SQL library is implemented asynchronously and you cannot avoid it. BUT you can handle it elegantly with Promises which are ES6 features:
(I didn't test the code but I think it should work)
function search_people_step2(user_id, search_criteria, user_friend)
{
return new Promise((resolve,reject)=>{
var first_name_friends = [];
var last_name_friends = [];
var placeHolders=user_friend.map(()=>"?").join(",");
con.query("SELECT first_name, second_name FROM user WHERE userid IN ("+placeHolders+")",user_friend,(err,rows)=>{
if(err)
reject(err);
else{
rows.forEach(row=>{
first_name_friends.push(row.first_name);
last_name_friends.push(row.second_name);
});
resolve({first_name_friends,last_name_friends});
}
});
});
}
And call your function like this :
search_people_step2(id,crit,friends).then(result=>{
//handle result asynchronously as there is no choice
console.log(result.first_name_friends);
console.log(result.last_name_friends);
}).catch(err=>{
//handle error
});
You are right, your problem is the asynchronous nature of the mysql call. You have to provide a callback to your search_people_step2 function.
You may change it like this:
search_people_step2(user_id, search_criteria, user_friend, callback)
In your function body you may use a library called async to handle all the callbacks properly. Here is an example for the usage:
async.eachSeries(user_friend, function(item, eachCb){
con.query("SELECT first_name, second_name FROM user WHERE userid = ?",
user_friend[i],function(err, rows) {
if(err) {
eachCb('error');
}
else {
if(rows.length == 0){
//nothing gets returned
eachCb(null);
}
else {
console.log(rows);
first_name_friends.push(rows[0].first_name);
last_name_friends.push(rows[0].second_name);
eachCb(null);
}
}
}, callback);
});
This calls each query in order on every item of the array and calls the inner callback if finished. When all items are processed or an error occured the outer callback is called. See the async library for further documentation.
simplest solution is
function search_people_step2(user_id, search_criteria, user_friend)
{
var first_name_friends = [];
var last_name_friends = [];
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
if(i==user_friend.length-1){
//do your work here which you want to perform in end
}
}
});
}
or use async library
var async = require('async');
var first_name_friends = [];
var last_name_friends = [];
async.series([function(cb){
function search_people_step2(user_id, search_criteria, user_friend)
{
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
if(i==user_friend.length-1){
cb()
}
}
});
}
},function(cb){
//do your work here
}],function(err){})

How to handle nodejs async with mysql?

Community,
I am new at nodejs and now i have a problem i cant solve: The async in javascript/nodejs. How can i handle the following so i can push the usernames to the array?
I already tried to help myself with many different functions but nothing works for me... :/
Sincerely Adhskid.
function getCurrentBetInformations () {
connection.query('SELECT * FROM `BETS` WHERE BET_ACTIVE = "1" LIMIT 1', function(err, rowss, fields) {
if (err) logger.warn('MySQL Error: ' + err.stack);
betid = rowss[0].BET_ID;
betends = rowss[0].BET_END;
connection.query('SELECT * FROM `BETS_BID` WHERE BID_BET_ID=\'' + betid + '\'', function(err, betbids, fields) {
if (err) logger.warn('MySQL Error: ' + err.stack);
var betQuants = new Array();
var betIds = new Array();
var betUsernames = new Array();
var betDates = new Array();
var rowsAffected = betbids.length;
for(i=0; i < rowsAffected; i++) {
betQuants.push(betbids[i].BID_KEYS_COUNT);
betIds.push(betbids[i].BID_ID);
var betSender = betbids[i].BID_SENDER;
connection.query('SELECT `USER_NAME` FROM `USER` WHERE `USER_STEAMID` = \'' + betSender + '\' LIMIT 1', function(err, rows, fields) {
if (err) logger.warn('MySQL Error: ' + err.stack);
console.log(rows[0].USER_NAME);
addUsername(rows[0].USER_NAME);
});
function addUsername (currentUsername) {
betUsernames.push(currentUsername);
}
betDates.push(betbids[i].BID_TIME);
if(betUsernames.length === i) {
execSiteRef();
}
}
function execSiteRef() {
console.log(betUsernames);
sendUserSiteRefresh([betQuants, betIds, betUsernames, betDates], betends);
}
});
});
}
I think your problem comes from this part:
if(betUsernames.length === i) {
execSiteRef();
}
You should iinstead check if the betUsernames array is of the final size:
if(betUsernames.length === rowsAffected) {
execSiteRef();
}
maybe there is more errors though, I did not check closely.

Node.js + bluebird + JSON. JSON is not valid after modification

Trying to get API data.
I have problem with creating valid JSON after modification.
Data should looks like this: [{"1"},{"2"},{"3"}, ... ,{201},{202},{203}, ...]
but now: [{"1"},{"2"},{"3"}, ...],[{"201"},{"202"},{"203"}, ...]
Where is my mistake?
var Promise = require("bluebird");
var request = require('bluebird').promisifyAll(require('request'));
var fs = Promise.promisifyAll(require('fs'));
var ladders = {"hardcore":"hardcore", "standard":"standard"};
function getJSONsync(urls) {
var ladder = [];
Promise.map(urls, function(url) {
return request
.getAsync(url)
.spread(function (res, body) {
if (res.statusCode != 200) {
throw new Error('Unsuccessful attempt. Code: '+ res.statusCode);
}
return JSON.stringify(ladder.concat(JSON.parse(body).entries), "", 4);
})
.catch(console.error);
},{ concurrency: 10 })
.then(function(arr) {
fs.writeFileAsync('file.json', arr);
})
}
function setUrls(ladderName, offset, limit) {
var arr = [];
while(offset < 15000 ) {
arr.push('http://api.pathofexile.com/ladders/'+ladderName+'?offset='+offset+'&limit='+limit);
offset = offset + 200;
}
return arr;
}
getJSONsync(setUrls(ladders.hardcore, 0, 200));
Thx for help.
Sorry for my Eng.
Finally:
var Promise = require("bluebird");
var request = require('bluebird').promisifyAll(require('request'));
var fs = Promise.promisifyAll(require('fs'));
var ladders = {"hardcore":"hardcore","standard":"standard"};
function getJSONsync(urls) {
Promise.map(urls, function(url) {
return request
.getAsync(url)
.spread(function (res, body) {
if (res.statusCode != 200) {
throw new Error('Unsuccessful attempt. Code: '+ res.statusCode);
}
return JSON.parse(body).entries;
})
.catch(console.error);
},{ concurrency: 10 })
.reduce(function(a, b) { return a.concat(b) })
.then(function(arr) {
fs.writeFileAsync('file.json', JSON.stringify(arr, "", 4));
console.log(arr.length);
})
}
function setUrls(ladder, offset, limit) {
var arr = [];
while(offset < 15000 ) {
arr.push('http://api.pathofexile.com/ladders/'+ladder+'?offset='+offset+'&limit='+limit);
offset = offset + 200;
}
return arr;
}
getJSONsync(setUrls(ladders.hardcore, 0, 200));
Promise.map returns an array, so when you do ladder.concat you return another array, so it becomes [[{"1"}], [{"1", "2"}]
You should just remove concat:
return JSON.stringify(JSON.parse(body).entries, "", 4);
But if you want to use variable ladder you may ladder.push(JSON.stringify(JSON.parse(body).entries, "", 4)) and use it instead of arr returned variable

Access Multiple table concurrently Mysql Nodejs

I am trying to assing a structured array from two tables, First table select query from which the value in result fetch the ID and assing to the next query, Here is my code
var query = db.query('select * from orderdish'),
users = [];
query
.on('error', function(err)
{
console.log(err);
updateSockets(err);
})
.on('result', function(order,callback)
{
order.abc ='11';
order.OrderKOT=[];
var queryOrderKOT = db.query('select * from tblorderkot where order_Id='+ order.order_Id,function()
{
kotOrders = [];
queryOrderKOT
.on('error',function(err)
{
console.log(err);
updateSocket(err);
})
.on('result',function(orderKOT)
{
kotOrders.push(orderKOT);
})
.on('end', function()
{
console.log(kotOrders);
order.OrderKOT.push(kotOrders);
});
});
console.log(order);
users.push(order);
/* aa(function(){
});*/
})
.on('end', function()
{
// loop on itself only if there are sockets still connected
if (connectionsArray.length)
{
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
console.log("This is End Values");
updateSockets({ users: users });
}
});
It's setting order.OrderKOT to empty. I know the it got to be done with call back in query.on(result) but if I set it's not fetching me any result. Second Query queryOrderKOT is working but it's fetching value pretty late and it's not pusing value to order.OrderKOT. Suggesst me for fetching the value concurrently.
It is likely that the "end" event for the first query is occurring before the second queryOrderKot query has had a chance to complete.
You should experience the expected behavior if you move the main response logic from the "end" of query to the "end" or "result" of queryOrderKot.
After so much of head breaking finally found the solution for concurrent mysql nodejs check #kevin Reilly thanks for trying a lot. I found out what ever we tried was streaming query. Which will be do the process async. Now coming back to the callback I wrote following and it's working perfectly
var query = db.query('select * from orderdish', function (err, results, fields, callback) {
if (err) {
console.log("ERROR: " + err.message);
updateSockets(err);
}
else {
// length of results
var count = 0;
// pass the db object also if you wanna use the same instance
q2(count, results, callback);
}
});
function q2(count, results, callbacks) {
var queryOrderKOT = db.query('select * from tblorderkot where order_Id=' + results[count].order_Id, function (err, resultKOT, KOTFields, callback) {
console.log(resultKOT);
results[count].OrderKOT = resultKOT;
count++;
if (count < results.length) {
q2(count, results, callback);
}
else {
// do something that you need to do after this
console.log(results);
//callbacks(results);
}
});
}
Here is my whole Code,
var mysql = require('mysql')
var io = require('socket.io').listen(3000)
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'vsk',
database: 'hahaha'
})
var POLLING_INTERVAL = 3000, connectionsArray = [], pollingTimer;
db.connect(function (err) {
if (err) console.log(err)
})
var socketCount = 0, restID = 0;
var pollingLoop = function () {
var query = db.query('select * from orderdish'), users = [];
.on('error', function (err) {
console.log(err);
updateSockets(err);
}).on('result', function (order) {
console.log("THis is USerID" + order.order_Id);
order.abc = '11';
order.OrderKOT = [];
var queryOrderKOT = db.query('select * from tblorderkot where order_Id=' + order.order_Id);
kotOrders = [];
queryOrderKOT.on('error', function (err) {
console.log(err);
updateSocket(err);
}).on('result', function (orderKOT) {
kotOrders.push(orderKOT);
query.on('end', function () {
console.log("This is at end values");
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
console.log("This is End Values");
updateSockets({
users: users
});
}
});
}).on('end', function () {
console.log(kotOrders);
console.log("This is my KOT End");
order.OrderKOT.push(kotOrders);
users.push(order);
console.log(users);
//callback(kotOrders);
});
console.log(order);
});
};
io.sockets.on('connection', function (socket) {
console.log("New Connection Opened");
socket.on('restID', function (restIDs) {
console.log(restIDs);
restID = restIDs;
console.log('Number of connections:' + connectionsArray.length);
if (connectionsArray.length > 0) {
console.log("Here is the Pooling Loop");
pollingLoop();
}
});
socket.on('disconnect', function () {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}
});
connectionsArray.push(socket);
});
var updateSockets = function (data) { // adding the time of the last update data.time = new Date();
// sending new data to all the sockets connected connectionsArray.forEach(function(tmpSocket) {
// tmpSocket.volatile.emit('notification', data); console.log(data); tmpSocket.volatile.emit('notification', data); }); };

Synchronous mysql in Node.js

I know that node.js is event driven and I should do this async but i can't find in my mind a way to do it.
so, i have this
var querystr = "SELECT * FROM groups";
var result = "";
dbClient.query(querystr, function (err, res, fields) {
if (err) {
console.log(err);
return;
}
for(var i in res) {
result = result + "#" +res[i].name + " =";
for (var j in res[i].members.split(",")) {
var memberquery;
if (j.substr(0,1) == "#") {
memberquery = "SELECT name FROM groups WHERE id = "+j.substr(1, j.length-1);
} else {
memberquery = "SELECT username FROM users WHERE id= "+j;
}
dbClient.query(memberquery, function(err, memres, fields) {
var membername = "";
if (typeof memres[0].username == "undefined") {
membername = "#"+memres[0].name;
} else {
membername = memres[0].username;
}
result = result + " " + membername;
});
}
result = result + "\n";
}
});
The issue that makes it sync is the for inside.
basically i'm generating a document in the result variable where i check the groups and tell the members so the expected output is
Group1 = member, member
Group2 = member, member
I usually use a pattern like the one below for this type of problem. In a nutshell: get a list of things then call a function to handle the list; that function calls itself until the list is completed; gather up the results as you go in an accumulator; when the list is empty, return whatever you've accumulated through the callback. It's just another way of accomplishing what #Andrey Sidorov demonstrated in his response.
//cb is (err, res)
function getData(cb){
var querystr = "SELECT * FROM groups";
var result = "";
dbClient.query(querystr, function (err, res, fields) {
if (err)
cb(err);
else {
var groups = [];
for (var ndx in res)
groups = groups.concat(res[ndx].members.split(","));
getMembers(groups, [], cb);
}
});
}
function getMembers(members, sofar, cb){
var member = members.shift();
if (!member)
cb(null, sofar);
else {
var memberquery;
var params;
if (member.substr(0,1) == "#") {
memberquery = "SELECT name FROM groups WHERE id = ?";
params = [member.substr(1, member.length-1)];
} else {
memberquery = "SELECT username FROM users WHERE id = ?";
params = [member];
}
dbClient.query(memberquery, params, function(err, res) {
if (err)
cb(err);
else {
var membername = "";
if (typeof res[0].username == "undefined") {
membername = "#" + res[0].name;
} else {
membername = res[0].username;
}
sofar.push(membername);
getMembers(members, sofar, cb);
}
});
}
}
function do_queries( resultCallback )
{
var querystr = "SELECT * FROM groups";
var result = "";
var num_queries_left = 0;
dbClient.query(querystr, function (err, res, fields) {
if (err) {
console.log(err);
return;
}
// calculate number of invocations of second sub-query
for(var i in res)
num_queries_left += res[i].members.split(",").length;
for(var i in res) {
result = result + "#" +res[i].name + " =";
for (var j in res[i].members.split(",")) {
var memberquery;
if (j.substr(0,1) == "#") {
memberquery = "SELECT name FROM groups WHERE id = "+j.substr(1, j.length-1);
} else {
memberquery = "SELECT username FROM users WHERE id= "+j;
}
dbClient.query(memberquery, function(err, memres, fields) {
var membername = "";
if (typeof memres[0].username == "undefined") {
membername = "#"+memres[0].name;
} else {
membername = memres[0].username;
}
result = result + " " + membername;
num_queries_left--;
if (num_queries_left == 0)
{
resultCallback(result);
return;
}
});
}
result = result + "\n";
}
});
}
do_queries( function(result) {
console.log(result);
});