Can't get result outside the query function in express nodejs - node.js

I am trying to get the value of variable w_name outside query even I have defined w_name before query but cannot getting it after query. Please check the code and help:
connection.query('SELECT * FROM workstations WHERE id=?',[results[0].w_id],function(err,res,field){
w_name = res[0].name;
});
console.log(w_name);
console.log showing undefined but if I am putting console.log inside the query after w_name it is showing proper result. What's wrong in it?

connection.query(...params) is asynchronous function, which requires some time to read and get resulting data for query passed to it.
Defining console.log(w_name) prints undefined because result is not yet assigned to w_name variable. Whereas defining it inside callback function assigns value to w_name.
Check this article for understanding asynchronous javascript.
connection.query('SELECT * FROM workstations WHERE id=?',
[results[0].w_id],function(err,res,field){
w_name = res[0].name;
console.log(w_name);
});

NodeJs is asynchronous, It uses callback for the results.
The best solution as far as i know about your problem is given below:
async function myQuery(){
return new Promise((resolve,reject)=>{
connection.query('SELECT * FROM workstations WHERE id=?',[results[0].w_id],function(err,res,field){
resolve(res[0].name)
});
})
}
Now you can use then to get the value or use async await to get the value like this.
//this is where you would like to call that function.
async function index(){
let w_name = await myQuery()
console.log(w_name)
}

here you can use Promise() and resolve() the query of the result.
const w_name = await new Promise(function(resolve, reject) {
connection.query('SELECT * FROM workstations WHERE id=?', [results[0].w_id], function(err, res, field) {
if (err) throw err
resolve(res[0].name);
})
});
console.log(w_name);

Related

Redis Node - Get from hash - Not inserting into array

My goal is to insert the values gotten from a redis hash. I am using the redis package for node js.
My code is the following:
getFromHash(ids) {
const resultArray = [];
ids.forEach((id) => {
common.redisMaster.hget('mykey', id, (err, res) => {
resultArray.push(res);
});
});
console.log(resultArray);
},
The array logged at the end of the function is empty and res is not empty. What could i do to fill this array please ?
You need to use some control flow, either the async library or Promises (as described in reds docs)
Put your console.log inside the callback when the results return from the redis call. Then you will see more print out. Use one of the control flow patterns for your .forEach as well, as that is currently synchronous.
If you modify your code to something like this, it will work nicely:
var getFromHash = function getFromHash(ids) {
const resultArray = [];
ids.forEach((id) => {
common.redisMaster.hget('mykey', id, (err, res) => {
resultArray.push(res);
if (resultArray.length === ids.length) {
// All done.
console.log('getFromHash complete: ', resultArray);
}
});
});
};
In your original code you're printing the result array before any of the hget calls have returned.
Another approach will be to create an array of promises and then do a Promise.all on it.
You'll see this kind of behavior a lot with Node, remember it uses asynchronous calls for almost all i/o. When you're coming from a language where most function calls are synchronous you get tripped up by this kind of problem a lot!

NodeJS render result of MySQL query properly

I got a MySQL query where I ask for the values in a specific field with the help of the SELECT statement. My question is: How do I get the value of the query ? When I render the template with my current code I receive following output on my page [object Object]. I have the following Code:
var network;
function query(sql, callback) {
connection.query(sql, function(err, rows) {
if (err) {
callback(err, null);
} else {
callback(rows);
res.render('index.hjs', { Mysql : network });
console.log(network);
}
});
}
query("SELECT testString FROM test", function(results){
network = results;
});
There are a couple of corrections in your code. Nothing wrong but just good practice. In error callback, you are sending two arguments but in actual query callback function, you are using only one argument.
Second thing is that res will be undefined inside query function. (Of course, unless you have it inside request handler, which spoils the purpose of having it as a function)
Without your database structure and code structure, this is the best I can do to help you.

Node.JS MySQL query nested function returning array

function searchCoords(){
var result = result;
connection.query('SELECT * FROM monitoring', function(err, result){
if(err){
console.log(err);
}
return{
result: result};
});
}
That's my code. I'm using that code to find the last coordinates of some devices and display them in google maps. but i need to first be able to access the array from the ouside so i can do something like:
myModule.searchCoords().result
or
myModule.searchCoords()().result
However I still can't access the array (result) from the outside function, let alone from another module.
I've been reading on closures, scopes, nested functions, anonymous functions, etc. but i still can't find the solution. What am i doing wrong?
Problem is, that the query is asynchronous, so it can't return a value in the normal flow. If you pass a function when you call searchCoords, then that function can be called after the results come back - which could be after a long delay. This is necessary to prevent the program flow from being blocked whilst potentially long operations are in process.
// accept a callback function to execute after getting results...
function searchCoords(callback){
var result = result;
connection.query('SELECT * FROM monitoring', function(err, result){
if(err){
console.log(err);
}
// run the callback function, passing the results...
callback({result: result});
});
}
// call like this...
// pass a function accepting results object that will be executed as callback
// once results have been returned...
searchCoords(function(resultsObject){
console.log(resultsObject.result)
})

Query callback with arguments and synchronous queries

I have two problems implementing a RESTful service using Node.js / node-postgres lib / PostgreDB and both are due to the async nature of JS.
A) I need to pass an extra argument to a callback in client.query(query, callback) call
I am inside a callback of a query and going through an array of recently fetched rows from a DB and want to launch a subsequent query for each of them:
var query = client.query('SELECT * FROM event', queryAllEventsHandler);
function queryAllEventsHandler(err, result){
allEvents = result.rows;
/* allEvents is an JSON array with the following format
[ {"id_event":1, "name":"name of the event"},
{"id_event":1, "name":"name of the event"}
]
*/
for(var i = 0; i<allEvents.length; i++){
client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( err, result){
//I want to have a reference to variable i
}
}
In the above example I want to do something like:
client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( AN_EXTRA_ARG, err, result)
Where the AN_EXTRA_ARG is an extra argument or a closure in the callback function... How can I achieve this? Should I create an closure with the of i and pass it as a callback's arg? How ? :|
B) "Synchronizing" queries
I need to launch various queries and create a custom JSON from all of them. Since every query and it's callback are asynchronous (waiting for no one) I was looking for a way to "tame" it and among other stuff I found a solution that occured to me in the first place, but seemed a bit "bad/lousy":
Keeping the query count is really the way to go as #jslatts suggests in Synchronous database queries with Node.js?
Hope I
With regards to question A, you could create a function to handle both your queries and only return when the last query is executed and return both results to the callback.
for(var i = 0; i<allEvents.length; i++){
query(client, allEvents[i], function(result1, result2) {
//do something
});
}
function query(client, event, callback) {
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err1, result1){
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err2, result2){
callback(result1, result2);
});
});
}
I don't like answering my on question, but this might be of interest to someone.... Regarding the A part of my question. You can assign a custom object to this in your function.
As you know a keyword this corresponds to the Window (top) object when inside a function (unless it's a method function). Using the bind function you can change the reference of this to your own object...
So what I did was, I created a named function queryCallback
function queryCallback(err, result){
//this == Window (default)
}
changed the anonymous callback function to the named one queryCallback:
client.query('SELECT * ... where id_event = $1',[allEvents[i].id_event], queryCallback.bind( {"position":i}, err, result));
Now, note queryCallback.bind( {"position":i}, err, result));
What bind(my_custom_this, [other args]) does is it binds a custom object (in my case {"position":i}) to this inside the function upon which the bind was called...
Now we have this scenario:
function queryCallback(err, result){
//this == {"position":i}
}
Bind explained: http://fitzgeraldnick.com/weblog/26/
A) I personally like lodash (or underscore if you prefer) partial() for this. It takes a function and a number of arguments and returns a function with the provided arguments applied and the remaining arguments still open. It's very much like the functional concept of currying.
B) For combining multiple asynchronous results I highly recommend async. The syntax will take a little getting used to, but makes thing like this very easy. Quick sample:
async.parallel([
one: function(callback){
db.fetch(options, callback);
},
two: function(callback){
db.fetch(options, callback);
}
],
function(err, results){
// this callback will get called when either parallel call gives an error
// or when both have called the callback
if (err) {
// handle error
return;
}
// get the results from results.one and results.two
});
== Added in edit ==
Actually lodash also provides a nicer (imho) albeit slightly more expensive (due to function calls) solution for your problem A):
_(allEvents).each(function(event, index, array) {
client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err, result) {
// Just use 'index' here, which doesn't change during the each
}
});
For B), your options include async or via a Promise library (such as Q, when.js, Bluebird, etc...)

Sending multiple query results to res.render() using node-mysql and mysql-queue

I [new to node.js and programming in general] have two mysql query results (member info and list of workshops that members can attend) and need to send them to res.render() to be presented in .jade template (Member edit page).
To do this I'm using node-mysql and mysql-queue modules. Problem is I don't know how to pass callback function to render the response before queue.execute() finishes so I made workaround and put first two queries in the queue (mysql-queue feature), executed the queue, and afterwards added third "dummy query" which has callback function that renders the template.
My question is can I use this workaround and what would be the proper way to this using this modules?
exports.memberEdit = function (req, res) {
var q = connection.createQueue();
var membersResults,
htmlDateSigned,
htmlBirthDate,
servicesResults;
q.query("SELECT * FROM members WHERE id= ?;", req.id, function (err, results) {
console.log("Članovi: " + results[0]);
membersResults = results[0];
htmlDateSigned = dater.convertDate(results[0].dateSigned);
htmlBirthDate = dater.convertDate(results[0].birthDate);
});
q.query("SELECT * FROM services", function (err, results) {
console.log("Services: " + results);
servicesResults = results;
});
q.execute();
// dummy query that processes response after all queries and callback execute
// before execute() statement
q.query("SELECT 1", function (err,result) {
res.render('memberEdit', { title: 'Edit member',
query:membersResults,
dateSigned:htmlDateSigned,
birthDate:htmlBirthDate,
services:servicesResults });
})
};
I think an alternative could be to use a transaction to wrap your queries with:
var trans = connection.startTransaction();
trans.query(...);
trans.query(...);
trans.commit(function(err, info) {
// here, the queries are done
res.render(...);
});
commit() will call execute() and it provides a callback which will be called when all query callbacks are done.
This is still a bit of a workaround though, it would make more sense if execute() would provide the option of passing a callback (but it doesn't). Alternatively, you could use a module which provides a Promise implementation, but that's still a workaround.

Resources