Synchronous request with mysql query in nodejs - node.js

I am working on node.js with express framework and I am trying to call multiple mysql queries and each query depend upon the previous queries.
How can be execute query in synchronously.
function f1(id, cb) {
$sql = "SELECT * FROM s1 where process_id=" +id;
connection.query(
$sql,
function (err, result) {
if (err) {
cb(err, null);
} else {
var str = '';
if (result.length > 0) {
for(val in result) {
$sql = "SELECT attribute_name FROM s2 where id=" + result[val].id;
connection.query(
$sql,
function (err, attrresult) {
if (err) {
cb(err, null);
} else {
if (result.length > 0) {
str += attrresult[0].attribute_name;
}
}
}
);
}
}
cb('', str);
}
}
);
}
router.get('/', function(req, res, next) {
f1('27', function (err,respose) {
console.log(respose);
});
});
Please suggest. How can we do this.
Thanks in advance.

you can use promise chaining, or async package to handle series execution, step by step
check the below guide for promise chaining
https://coderwall.com/p/ijy61g/promise-chains-with-node-js
for async check the following package
https://github.com/caolan/async

Node I/O is async by definition. I think your problem is the for loop. It loops all the iterations before the matching-per-variable nested query callback. So use some mechanism to achieve the desired flow of execution. You can use promises, there are several good libs(Q,Bluebird,native promises with ES2015...) Also you can use async.js wich is easier to deal with it.
The libs are not mandatory but they do the work easier.

As everybody said, Async.js is a nice solution to do this kind of thing.
However it could be a little hard to handle at the beginning. If you like to have a little more abstraction, I would suggest you to use a framework like Danf (build upon Express). This framework abstracts Async.js to handle asynchronicity (execute operations in series, in parallel, ...) in an original and simple way. Take a look at the overview to understand what I mean.

You can't really make the synchronous, but you can make then look like sync code by making use of promises and generators.
function mySexyMethod() {
return new Promise(function (resolve, reject) {
someAsyncethod(params, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
})
});
}
Express router
var wrap = require('co-express');
router.verb('some-route', wrap(function* (req, res, next) {
var val, val2;
try {
val = yield mySexyMethod();
val2 = yield anotherPromiseThatRequiresPreviousVal(val);
} catch (e) {
return next(e);
}
});
Even better, look into https://www.npmjs.com/package/bluebird and check if whatever mysql lib you are using can be promisified.

Related

Await is not pausing execution

I can't figure out why execution continues, and await isn't pausing execution until the called function returns.
In a node.js application
Contacts.js
async function routes (fastify, options) {
fastify.get('/contact', async (req, reply) => {
let lookup = require('../helpers/validate_school');
let school_info = await lookup.validate(req.hostname.split('.')[0]);
console.log('here: ', school_info);
let school = school_info.school;
...
reply.view('application/application.html', school);
});
};
school.lookup.js
async function validate(hostname){
const con = require('../../config/db').getDb();
let ret = {};
console.log('lets check for school info');
await con.query('SELECT * FROM schools where identifier=? LIMIT ?', [hostname, 1], function(err, res, fields){
if (err) throw err;
if (res.length > 0){
ret.school = JSON.stringify(res[0]);
...
console.log('found: ', ret);
return ret;
} else {
console.log('not found: ', ret);
return ret;
}
});
};
module.exports = {validate: validate};
log
lets check for school info
here: undefined
found: {
school: '{"id":2,"name":"Second School","school_dbid":"2","primary_color":"purple","secondary_color":"lavender","tertiary_color":"green","quaternary_color":"blue","identifier":"school2","mascot_id":1,"created_at":"2019-11-20T05:22:16.864Z","updated_at":"2019-11-21T17:59:11.956Z"}',
...
}
How can I ensure that lookup.validate returns before proceeding in the code block?
The entire point of await is so that you do not have to use the callback. Instead it will just return the data to you or throw an error on reject. You need to pick one, either use just the callback or just async/await.
That being said, async/await only works on promises. But the mysql library does not use promises. So you can't even use async/await in this situation anyway, if you are using mysql and not mysql2.
Plus, callbacks will not return anything. Return statements do not work in asynchronous scenarios.
You have two options. Deal with the asynchronicity of the callback and use the value directly:
con.query('SELECT * FROM schools where identifier=? LIMIT ?', [hostname, 1], function(err, res, fields){
// The result cannot leave this callback.
// Anything you need to do with the result must be done here.
});
Or if you are using mysql2 you can use a promise like this:
const data = await con.promise().query('your query');

Node Functions Return Nothing sqlite3

I'm trying to use sqlite3 in a project and I'm running into a problem. My functions aren't returning any values. I added a console.log before the return statement and oddly enough, it works, but logs after the function has returned.
console.log(getNext());
function establishConnection(callback) {
const db = new sqlite3.Database('database.db');
db.serialize(() => {
callback(db);
});
db.close();
}
function getNext() {
establishConnection(db => {
db.get('SELECT col1, col2 FROM table ORDER BY priority LIMIT 1;', (err, row) => {
console.log([row.col1, row.col2]); // works
return [row.col1, row.col2]; // doesn't work
});
});
}
I'm no expert at Node but this seems like something that should work and I don't understand why it doesn't. Could someone please explain this to me and possibly provide a solution?
getNext is asynchronous, this is why you see logging after the function "returns". Your code currently uses callback style so this answer will follow your format. Using promises or async/await is a more modern approach.
getNext(result => console.log(result));
function establishConnection(callback) {
const db = new sqlite3.Database('database.db');
db.serialize(() => {
callback(db);
});
db.close();
}
function getNext(callback) {
establishConnection(db => {
db.get('SELECT col1, col2 FROM table ORDER BY priority LIMIT 1;', (err, row) => {
callback([row.col1, row.col2]);
});
});
}

rethinkdb & nodejs: save result in var

it's possible save result query of rethinkdb in a variable?
Like this??
var test = r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run()
now I use this method
var test;
r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run().then(function(response){
test = response;
})
If you don't like using promises and are using the latest version of ECMAScript, you can use async/await, which provides syntactic sugar to let you write your asynchronous code as if it were synchronous.
You could rewrite your example like this:
async function getTest() {
var test = await r.db('chat').table('group_chat').count(r.row('passengers').contains(function(passeggers) {
return passeggers('nome').eq('pigi');
})).run();
return test;
}
Note that “behind the scenes”, this still uses promises, but it makes the code easier to read and understand.
Simplest yet working solution would be as bellow, using callback
function getTest(callback) { // add callback
r.db('chat')
.table('group_chat')
.count(r.row('passengers')) // you forgot closing brace here
.contains(function(passeggers) {
return passeggers('nome').eq('pigi')
})
.run()
.then(function(result) {
callback(null, result); // call callback with result
})
.error(function(err) {
callback(err, null); // call callback with error
});
}
getTest(function(err, result) { // invoke callback
if (err) throw err;
console.log(result)
var test = result; // note: you can use test variable only inside this call
})

Parallel calls and wait condition in NodeJS with Q or Async

I'm trying to retrieve products basis by categories, I'd like to parallel the process, first I'm not able to figure out how to write wait condition or ideal a call back method to let parent function know that all products have been retrieved from database.
I'd be open to all solution, ideally here I have used Async but want to prefer Q (https://github.com/kriskowal/q/wiki/Examples-Gallery) which seems to be much better choice with Mongoose and MongoDB operations.
var temp = []
Async.each([1,2,3,4,5,6,7,8,9...n],
function (item, callback) {
database.getProductsByTaxonomy(item, function (err, products) {
temp = new Object();
temp.TaxonomyID = item;
temp.Products = products;
results.push(temp);
callback(err, products);
});
},
function (err) {
console.log(err);
});
<<wait for all .each call completes>>
return temp; // or callback (err, temp); // or emit?
Any solutions?
You can use my Qx library, which simplifies working with Q and arrays:
return Qx.map(arr, function (item) {
return getPromiseFromDb(item).then(function(products) {
return { taxonmyId: item, products: products };
});
});
If your DB uses callbacks rather than promises, you can use Q.ninvoke() to turn it into a promise.

Sequential execution in node.js

I have code like
common.findOne('list', {'listId': parseInt(request.params. istId)}, function(err, result){
if(err) {
console.log(err);
}
else {
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks) {
console.log(tasks[i]);
common.findOne('tasks', {'taskId':parseInt(tasks[i])}, function(err,res){
tArr[i] = res;
console.log(res);
});
}
console.log(tArr);
}
return response.send(result);
}
});
It is not executed sequentially in node.js so I get an empty array at the end of execution. Problem is it will first execute console.log(tArr); and then execute
common.findOne('tasks',{'taskId':parseInt(tasks[i])},function(err,res){
tArr[i] = res;
console.log(res);
});
Is there any mistake in my code or any other way for doing this.
Thanks!
As you are probably aware, things run asynchronously in node.js. So when you need to get things to run in a certain order you need to make use of a control library or basically implement it yourself.
I highly suggest you take a look at async, as it will easily allow you to do something like this:
var async = require('async');
// ..
if(result.tasks) {
async.forEach(result.tasks, processEachTask, afterAllTasks);
function processEachTask(task, callback) {
console.log(task);
common.findOne('tasks', {'taskId':parseInt(task)}, function(err,res) {
tArr.push(res); // NOTE: Assuming order does not matter here
console.log(res);
callback(err);
});
}
function afterAllTasks(err) {
console.log(tArr);
}
}
The main things to see here is that processEachTask gets called with each task, in parallel, so the order is not guaranteed. To mark that the task has been processed, you will call callback in the anonymous function from findOne. This allows you to do more async work in processEachTask but still manage to signify when it is done. When every task is done, it will then call afterAllTasks.
Take a look at async to see all the helper functions that it provides, it is very useful!
I've recently created a simple abstraction named "wait.for" to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
Using wait.for and async your code will be:
var wait = require('waitfor');
...
//execute in a fiber
function handleRequest(request,response){
try{
...
var result = wait.for(common.findOne,'list',{'listId': parseInt(request.params.istId)});
var tArr = new Array();
if(result.tasks) {
var tasks = result.tasks;
for(var i in tasks){
console.log(tasks[i]);
var res=wait.for(common.findOne,'tasks',{'taskId':parseInt(tasks[i])});
tArr[i] = res;
console.log(res);
}
console.log(tArr);
return response.send(result);
};
....
}
catch(err){
// handle errors
return response.end(err.message);
}
};
// express framework
app.get('/posts', function(req, res) {
// handle request in a Fiber, keep node spinning
wait.launchFiber(handleRequest,req,res);
});

Resources