Run multiple MySQL queries in this node.js function - node.js

I have this node.js function which returns a Promise after executing a single MySQL query.
function deletePoint(PointObj, door_id) {
return new Promise(function(resolve, reject) {
try {
var connection = jonMySQL.getMySQL_connection();
var mysql_query = '`DELETE FROM table1 WHERE user_id=? and door_id=?`';
var mysql_query_placeholder_arr = [PointObj.user_id, door_id];
connection.query(mysql_query, mysql_query_placeholder_arr, function(err, rows, fields) {
if (err) {
return reject(err);
} else {
resolve(rows);
}
});
} catch (err) {
reject(err);
}
});
}
The above function works fine. However, what if I would like the function to finish running 2 MYSQL queries?
The second query would look something like this;
var mysql_query2 = '`DELETE FROM table2 WHERE user_id=? and door_id=?`';
var mysql_query2_placeholder_arr = [PointObj.user_id, door_id];
How do I integrate this second MySQL query into the function such that the Promise will return only after both queries have been executed?
EDIT: It would be preferable if the answer provided can handle up to several queries (say, up to 5) without callback hell. Can someone provide an answer using async module?

I would suggest to create a generalized method to execute queries, you can modify it as per your requirement.
Note: running sequentially you have to manage the row that you are returning in resolve(rows). In parallel all the rows gets produced in final successCallback result parameter as array of objects.
function deletePoint(PointObj, door_id){
var query = {
text : '`DELETE FROM table1 WHERE user_id=? and door_id=?`',
placeholder_arr : [PointObj.user_id, door_id],
};
var query2 = {
text : '`DELETE FROM table2 WHERE user_id=? and door_id=?`',
placeholder_arr : [PointObj.user_id, door_id],
};
//do this if you want to execute the queries sequentially
mySQLQuery(query).then(mySQLQuery(query2)).then(successCallback).catch(errorCallback);
//do this if you want to execute the queries parallely
var query_arr = [mySQLQuery(query),mySQLQuery(query2),...];
Promise.all(query_arr).then(successCallback,errorCallback)
function successCallback(result){
console.log('done',result);
}
function errorCallback(err){
console.log('Error while executing SQL Query',err);
}
}
function mySQLQuery(query) {
var connection = jonMySQL.getMySQL_connection();
return new Promise(function(resolve, reject) {
try {
connection.query(query.text, query.placeholder_arr, function(err, rows, fields) {
if (err) {
return reject(err);
} else {
return resolve(rows);
}
});
} catch (err) {
return reject(err);
}
});
Besides, you can always use async module,
async.parallel for parallel execution,
async.waterfall for sequential execution with values passed from one function to other or
async.series if no values need to be passed between sequential functions.

Try like this
function deletePoint(PointObj, door_id) {
return new Promise(function(resolve, reject) {
try {
var connection = jonMySQL.getMySQL_connection();
var mysql_query = 'DELETE FROM table1 WHERE user_id = ? and door_id = ?';
var mysql_query_placeholder_arr = [PointObj.user_id, door_id];
connection.query(mysql_query, mysql_query_placeholder_arr, function(err, rows1, fields) {
if (err) {
return reject(err);
} else {
var mysql_query2 = 'DELETE FROM table2 WHERE user_id = ? and door_id = ?';
var mysql_query2_placeholder_arr = [PointObj.user_id, door_id];
connection.query(mysql_query, mysql_query_placeholder_arr, function(err, rows2, fields) {
if (err) {
return reject(err);
} else {
resolve({
rows1: rows1,
rows2: rows2
});
}
});
}
});
} catch (err) {
reject(err);
}
});
}
Suggestion
It's not the better approach to writing multiple queries in a callback.
To resolve such type of case use async module with parallel or waterfall methods based on scenario

Related

Returning the result of a node-postgres query

I am attempting to return the result of a node-postgres query and store it in a variable. I can manage a console.log just fine, but cannot find a way to return the result so that it is accessible outside of the query method. I'm at a loss, and know I must be missing something obvious (or multiple obvious things), because if it isn't possible to do this I don't understand the point of node-postgres since all I will ever be able to do is log my results to the console.
I have tried the code below, along with a version using promises, and both receive the same result, 'undefined.' A console.log within the else works fine, but a return does not make the result accessible to the rest of the function. In the code below, my return comes back as 'undefined' as would a console.log in its place.
var selectFrom = function(data, table, condition) {
var queryResult;
pool.query(`SELECT ${data} FROM ${table} ${condition}`, function(err, result) {
if(err) { console.log(err); }
else { queryResult = result.rows[0][data]; }
})
pool.end();
return queryResult;
}
var result = selectFrom('amount','total_nonfarm_monthly_sa', `WHERE month='2019-08-31'`);
console.log(result);
This is what you are looking for:
async function selectFrom(data, table, condition) {
try {
const res = await pool.query(
`SELECT ${data} FROM ${table} ${condition}`
);
return res.rows[0][data];
} catch (err) {
return err.stack;
}
}
Outside of the previous function:
async function whateverFuncName () {
var result = await selectFrom('amount','total_nonfarm_monthly_sa', `WHERE month='2019-08-31'`);
console.log(result);
}
EDIT: I didn't run this code snippet but the main concept is pretty straightforward.
The "query" method is an async call, you should use async/await or Promise.
With async/await:
await client.connect()
const res = await client.query("SELECT amount FROM total_nonfarm_monthly_sa WHERE month='2019-08-31'");
console.log(res.rows[0]);
await client.end();
Edit:
I can see that there's an option of callback, but I would use the async/await
You need to use callbacks:
var selectFrom = function(data, table, condition, callback) {
pool.query(`SELECT ${data} FROM ${table} ${condition}`, function(err, result) {
if(err)
return callback(err);
callback(null, result.rows[0][data]);
})
pool.end();
}
selectFrom('amount','total_nonfarm_monthly_sa', `WHERE month='2019-08-31'`, function(err, result){
console.log(err, result);
});
or promises:
var selectFrom = function(data, table, condition) {
return new Promise(function(resolve, reject){
pool.query(`SELECT ${data} FROM ${table} ${condition}`, function(err, result) {
if(err)
return reject(err);
resolve(result.rows[0][data]);
})
pool.end();
});
}
selectFrom('amount','total_nonfarm_monthly_sa', `WHERE month='2019-08-31'`)
.then(function(result){
console.log(result);
}).catch(function(err){
console.log(err);
});

node.js async/sync with For Loop, Query, and Additional function

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

Asynchronous function - node.js

I have a question about asynchronous function. Here my function "My_function":
function My_function (my_name, callback){
stmt = db.prepare ("SELECT number_table1 from my_table1 WHERE user=?");
stmt.bind(my_name);
stmt.get(function(error,row){
if(error){
throw err;
}
else{
if(row){
callback(number_table1);
}
else{
console.log("error");
}
}
});
}
Work fine but I have 2 tables and I need do other query and I need add two numbers so... in my function I need do too this query:
stmt = db.prepare ("SELECT number_table2 from my_table2 WHERE user=?");
and finally return back in my callback "number_table1 + number_table2".
Somebody know how to solve it? Thanks in advance.
Best regards!
In cases like your's I like to use the async module, because the code will be more legible. Example:
var async = require('async');
function My_function(my_name, callback) {
var stmt = db.prepare("SELECT number_table1 from my_table1 WHERE user=?");
stmt.bind(my_name);
stmt.get(function (error, row) {
if (error) {
callback(error, null);
} else {
if (row) {
callback(null, number_table1);
} else {
callback(new Error("row not found"), null);
}
}
});
}
//if you need the results in a specific order, you can use "series" instead of "parallel".
async.parallel(
//array of functions
[
function (callback) {
My_function('firstName', callback);
},
function (callback) {
My_function('secondName', callback);
}
],
//results when all functions ends
//the results array will equal [number_table1, number_table2], but the order can be different, because of the parallelism
function (err, results) {
if (err) {
//handle the err
} else {
//do something
}
}
);
Docs:
http://caolan.github.io/async/docs.html#parallel or
http://caolan.github.io/async/docs.html#series
You need to synchronize the functions so that you can be sure both their results are ready before calling back. You can do this using promises: https://www.promisejs.org/
Make two regular functions (no callbacks), one for each query (function1, function2)
Make both return a promise
Then you can do
function My_function(my_name) {
var value1;
function1(my_name)
.then(function(resultFromFunction1) {
value1 = resultFromFunction1;
return function2(my_name);
})
.then(function(resultFromFunction2) {
var result = value1 + resultFromFunction2;
return result;
});
}
}
Make sure to catch errors and handle different outcomes, what I presented is its simplest form.
Update
Here is an example of a function doing a query and returning a promise
function1 = function(user) {
return new Promise(function (resolve, reject) {
pool.getConnection(function (err, connection) {
if(err) {
reject ({status : false, message : "Error in connection database"});
} else {
connection.query('SELECT number_table1 from my_table1 WHERE user=?', [user], function(err, rows){
connection.release();
if(!err) {
resolve ({status: true, message: rows});
} else {
reject ({status: false, message: err});
}
});
}
});
});
}
Make the table names function parameters. Convert that function to use async/await or promise. Use Promise.all to run both queries.

NodeJS Promises - "Then" not called

I'm new to NodeJS and after spending a few hours trying to understand how Promises work exactly, what seems to be an easy thing still doesn't work.
I'm trying to make a few calls to a database, and once all of those calls are done, do something else. What I have now is the following code, but none of the then-functions are called.
var queries = ['SELECT value FROM tag', 'SELECT url FROM download_link'];
console.log("Starting promises");
var allPromise = Promise.all([queryDatabaseAddToResult(connection, queries[0], result), queryDatabaseAddToResult(connection, queries[1], result)]);
allPromise.then(
function(result) {
console.log("1"); // Does not show up
}, function(err) {
console.log("2"); // Does not show up either
}
);
function queryDatabaseAddToResult(connection, query, result) {
return new Promise(function(resolve, reject) {
connection.query(query, function(err, rows, fields) {
if (err) {
console.log(err);
Promise.reject(err);
}
console.log(rows);
result.tags = JSON.stringify(rows);
Promise.resolve(result);
});
})
}
The calls to the database do get made, as logging the rows show up in the log.
The problem is that you are not calling the correct resolve and reject functions. It should be:
function queryDatabaseAddToResult(connection, query, result) {
return new Promise(function(resolve, reject) {
connection.query(query, function(err, rows, fields) {
if (err) {
console.log(err);
reject(err);
} else {
console.log(rows);
result.tags = JSON.stringify(rows);
resolve(result);
}
});
})
Note that the resolve and reject calls should not be scoped with Promise.. And you should have used an else to avoid calling resolve once you've called reject.
you have to do like this:
var promise1 = queryDatabaseAddToResult(connection, queries[0], result);
var promise2 = queryDatabaseAddToResult(connection, queries[1],result);
Promise.all([prromise1, promise2]).then(result => {
console.log(1);
}).catch(err => {
console.log(err);
});
return Promise.reject() //no need to add else part

Do something async with underscore map

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

Resources