variable value becomes undefined in NodeJS ExpressJS - mysql

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

Related

How to use result array of a query in another query in Mysql+Node JS?

I want to use the result of first query(sql1) in second query(sql2). The result of first query(sql1) is getting in .ejs page but no result for the second query(sql2).
var sql1 = 'SELECT * FROM `Rooms`';
con.query(sql1,function(err,rows,fields){
if(!err)
{
var count=rows.length;
for(i=0;i<count;i++)
{
arr_room[i]=rows[i].room_name;
}
}
else
{
console.log('error...');
}
});
var sql2 = 'SELECT * FROM Lights WHERE room_name =? ' ;
con.query(sql,arr_room[0],function(err,rows,fields){
if(!err)
{
var count=rows.length;
for(i=0;i<count;i++)
{
arr_icon[i]=rows[i].icon;
}
}
else
{
console.log('error...');
}
res.render('lighting',{arr_icon,arr_room});
});
You need to nest sql2 into sql1, in nodejs everything is asynchronous, that means you must wait for something to finish first.
And you had a typo on the second query, you called sql instead of sql2
var sql1 = 'SELECT * FROM `Rooms`';
con.query(sql1, function(err, rows, fields) {
if (!err) {
var count = rows.length;
//for (i = 0; i < count; i++) {
// arr_room[i] = rows[i].room_name;
//}
if (count) {
// simplified version instead of for
var arr_room = rows.map(i => i.room_name);
// you can safely use it inline since data comes straight from the database
// query will use `in` condition: room_name in ('roomX','roomY', 'roomZ')
var sql2 = `SELECT * FROM Lights WHERE room_name in ('${arr_room.join("','")}') `;
con.query(sql2, function(err, rows, fields) {
if (!err) {
var count = rows.length;
for (i = 0; i < count; i++) {
arr_icon[i] = rows[i].icon;
}
} else {
console.log('error...');
}
res.render('lighting', {
arr_icon,
arr_room
});
});
} else {
console.log('no records to pass for sql2');
}
} else {
console.log('error...');
}
});
I know this question has an answer already, but I wanted to contribute a SQL-only solution: using a subquery instead of executing two separate queries and operating on their results in Node.js.
SELECT
*
FROM lights
WHERE
room_name IN (
SELECT room_name FROM rooms
);

Return boolean value from MYSQL in NodeJS

Im working on a function which will return a boolean-value. This value represents if an user exists in the database. Currently I have this:
function checkIfExists(){
var sql = "SELECT * FROM Users WHERE user = " + mysql.escape(req.body.username);
var rows = 0;
database.query(sql, function(err, result, fields){
console.log(result.length);
rows += result.length;
});
return rows > 0;
}
console.log(checkIfExists());
I use 'console.log(result.length)' to validate if there are results. When I test some input, I got this:
false
1
This is strange because there is one result, so rows should be equal to 1. But then it returns false instead of true. Is it possible that the value of rows isn't changed in 'database.query(...' ?
Because your function checkIfExists is asynchronous, I think you sould use callback system like this :
function checkIfExists(callback) {
var sql = "SELECT * FROM Users WHERE user = " + mysql.escape(req.body.username);
var rows = 0;
database.query(sql, function (err, result, fields) {
if (err) {
callback(err, null);
}
else {
console.log(result.length);
rows += result.length;
callback(null, rows > 0);
}
});
}
checkIfExists(function(err, isExists) {
if (err) {
// An error occured
}
else {
console.log(isExists);
}
});
EDIT
You also can simlify your checkIfExists function like this :
function checkIfExists(callback) {
var sql = "SELECT * FROM Users WHERE user = " + mysql.escape(req.body.username);
database.query(sql, function (err, result) {
callback(err, result ? result.length > 0 : false);
});
}
More information here :
Understanding Async Programming in Node.js
Hope it helps.

NodeJS and MySQL: getting array data inside query callback

I'm trying to run this piece of code:
setInterval(function () {
var params = {
QueueUrl: 'https://sqs.us-east-1.amazonaws.com/821808622769/Teste', // required
MaxNumberOfMessages: 10
};
sqs.receiveMessage(params, function (err, data) {
if (err)
console.log('Erro de SQS:' + err);
else {
var retorno = data.Messages;
for (var i in data.Messages) {
var queryString = 'SELECT now()'; //dummy query, just for tests
db_connection.query(queryString, null, function (err, rows, fields) {
if (err) {
console.log('Erro no BD:' + err);
return;
}
var date = new Date();
console.log(retorno[i].Body + ' ' + date.getTime().toString());
});
}
console.log();
}
});
}, 30000);
and I have 5 messages in AWS SQS, such as this:
but when I run my code, instead of having the retorno[i].Body of each message, sometimes I get a message repeated, as show in this image
My for loop is running from 1 to 5 queries, but how do I carry the retorno[i] inside the callback to the database query? I mean, how do I identify which message I was dealing with?
Using .bind() you can setting the internal version of i to be the same as the version of i in your loop.
.bind({i:i}) at the end of your callback and change the internal code to reference this.i
for (var i in data.Messages) {
var queryString = 'SELECT now()'; //dummy query, just for tests
db_connection.query(queryString, null, function(err, rows, fields) {
if (err) {
console.log('Erro no BD:' + err);
return;
}
var date = new Date();
console.log(retorno[this.i].Body + ' ' + date.getTime().toString());
}.bind({
i: i
});
}
}

How to save the result of MySql query in variable using node-mysql [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 1 year ago.
im trying to save the result of MySql query in variable using node-mysql model and node.js so i have this code:
connection.query("select * from ROOMS", function(err, rows){
if(err) {
throw err;
} else {
console.log(rows);
}
});
and the result is :
[ { idRooms: 1, Room_Name: 'dd' },
{ idRooms: 2, Room_Name: 'sad' } ]
so i need to store this results in variable so i try like this:
var someVar = connection.query("select * from ROOMS", function(err, rows){
if(err) {
throw err;
} else {
return rows;
}
});
console.log(someVar);
but is not working thanks for any help in advance.
Well #Fadi, connection.query is async, which mean when your call your console.log(someVar), someVar has not been set yet.
What you could do:
var someVar = [];
connection.query("select * from ROOMS", function(err, rows){
if(err) {
throw err;
} else {
setValue(rows);
}
});
function setValue(value) {
someVar = value;
console.log(someVar);
}
You can't do that because network i/o is asynchronous and non-blocking in node.js. So any logic that comes afterwards that must execute only after the query has finished, you must place inside the query's callback. If you have many nested asynchronous operations you may look into using a module such as async to help better organize your asynchronous tasks.
As a complement to already given answers.
var **someVar** = connection.query( *sqlQuery*, *callback function( err , row , fields){}* )
console.log(**someVar**);
This construction will return in someVar information of this connection and his SQL query . It will not return values ​​from the query .
Values ​​from the query are located in the callback function ( err , row , fields)
Here is your answer if you want to assign a variable to res.render
//before define the values
var tum_render = [];
tum_render.title = "Turan";
tum_render.description = "Turan'ın websitesi";
//left the queries seperatly
var rastgeleQuery = "SELECT baslik,hit FROM icerik ORDER BY RAND() LIMIT 1";
var son5Query = "SELECT baslik,hit FROM icerik LIMIT 5";
var query_arr = [rastgeleQuery, son5Query];
var query_name = ['rastgele', 'son5'];
//and the functions are
//query for db
function runQuery(query_arr,sira){
connection.query(query_arr[sira], function(err, rows, fields) {
if (err) throw err;
var obj = [];
obj[query_name[sira]] = rows;
sonuclar.push(obj);
if (query_arr.length <= sira+1){
sonuc();
}else{
runQuery(query_arr, sira+1);
}
});
}
//the function joins some functions http://stackoverflow.com/questions/2454295/javascript-concatenate-properties-from-multiple-objects-associative-array
function collect() {
var ret = {};
var len = arguments.length;
for (var i=0; i<len; i++) {
for (p in arguments[i]) {
if (arguments[i].hasOwnProperty(p)) {
ret[p] = arguments[i][p];
}
}
}
return ret;
}
//runQuery callback
function sonuc(){
for(var x = 0; x<=sonuclar.length-1; x++){
tum_render = collect(tum_render,sonuclar[x]);
}
console.log(tum_render);
res.render('index', tum_render);
}

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