Do not wait for mysql database result in node js - mysql

I tried to get result using mysql database query from called function but do not wait for result in called function. Following is my code for users.js file. I got result in getBankDetail function but do not get result in users function.
var db = require("../db/mysqlconnection");
function users(app){
app.get("/users",async function(req, res, next){
let bankDetail = await getBankDetail();
console.log("bankDetail",bankDetail); //Here I do not got result
return res.send(bankDetail);
});
}
async function getBankDetail(){
db.getConnection(async function(err, connection) {
if (err) throw err; // not connected!
await connection.query('SELECT * FROM bank', function (error, results, fields) {
connection.release();
if (error) throw error;
console.log("bank result",results); //Here I got result
return results;
});
});
}
module.exports = users;
My Question is why do not wait for result in called function? I also used async/await functionality.

function getBankDetail(){
return new Promise((resolve, reject) => {
db.getConnection(function(err, connection) {
if (err) reject(err); // not connected!
connection.query('SELECT * FROM bank', function (error, results, fields) {
connection.release();
if (error) reject(err);
console.log("bank result",results); //Here I got result
resolve(results);
});
});
});
}
And then you can use let bankDetail = await getBankDetail();
If you want to use await on your db.getConnection and connection.query you will have to use mysql2/promises library or promisify those functions yourself
Here is the implementation when you use the promisified version of your database driver:
async function getBankDetail(){
const connection = await db.getConnection();
const data = await connection.query('SELECT * FROM bank');
connection.release();
console.log("bank result", data[0]); //Here I got result
return data[0];
}

Related

Multiple Transactions in mysql for Node

I'm using node's driver for mysql and need to execute 'n' number of transactions one after the other and not simultaneously.
I've tried using a for/forEach loop but the transactions seem to happen concurrently and that causes my api to crash.Here's the error :-
throw err; // Rethrow non-MySQL errors
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
One single transactions seems to work just fine.
Each transaction has 4 queries, req.body is an array of objects:-
router.post('/production/add', (req, res) => {
for (const obj of req.body) {
pool.getConnection(function (err, connection) {
connection.beginTransaction(function (err) {
if (err) throw err;
const query1 = `select qty from production where prc_id = ${obj.prc_id}`;
console.log(query1);
connection.query(query1, function (error, result1, fields) {
if (error) {
return connection.rollback(function () {
res.status(400).send({ query: 1, message: error.sqlMessage, code: error.code, errno: error.errno });
return;
});
}
const new_prod_qty = result1[0].qty - obj.auth_prod_qty;
const query2 = new_prod_qty > 0 ? `update production set qty = ${new_prod_qty} where prc_id = ${obj.prc_id}` : `delete from production where prc_id = ${obj.prc_id}`;
console.log(query2);
connection.query(query2, function (error, results2, fields) {
if (error) {
return connection.rollback(function () {
res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
return;
});
}
const query3 = `update prc set auth_prod_qty = ${obj.auth_prod_qty} where prc_id = ${obj.prc_id}`;
console.log(query3);
connection.query(query3, function (error, results3, fields) {
if (error) {
return connection.rollback(function () {
res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
return;
});
}
const query4 = "select * from store";
connection.query(query4, function (error, results3, fields) {
if (error) {
return connection.rollback(function () {
res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
return;
});
}
connection.commit(function (err) {
if (err) {
return connection.rollback(function () {
res.status(400).send({ message: error.sqlMessage, code: error.code, errno: error.errno });
return;
});
}
res.status(201).send(results2);
});
});
});
});
});
});
});
};
});
Based off some research Sequelize ORM seems to promisify transactions but however I'm hoping to use it as a last resort. Any sort of solution with or without Sequelize would be appreciated!
Thanks in advance!
You need to use async / await to run your txs sequentially. How to do this?
Use npm mysql2 in place of npm mysql. That gets you promisified (awaitable) versions of the APIs when you require('mysql2/promise'). Plus, this is much more fun to program and debug than those miserable nested callbacks. Just don't forget the awaits.
Use this basic outline for your code's data processing loop. Everything will go in order sequentially. The way you create your pool is a little different; read the npm page. This is not debugged.
const mysql = require('mysql2/promise');
router.post('/production/add', async (req, res) => {
const connection = await pool.getConnection()
for (const obj of req.body) {
try {
await connection.beginTransaction()
const query1 = 'whatever'
const result1 = await connection.query(query1)
const query2 = 'something else'
const result 2 = await connection.query(query2)
/* etcetera etcetera */
await connection.commit()
}
catch (error) {
await connection.rollback()
pool.releaseConnection()
res.status(400).send({ something })
}
}
pool.releaseConnection()
}
mysql2/promise is exactly the package I was looking for, works with mysql and uses promise() method to upgrade mysql connection to a promise based mysql2 connection.
router.post('/stock/add', async (req, res) => {
const connection = pool.getConnection(async function (err, connection) {
if (err) {
connection.release();
res.status(400).send(err);
return;
}
else {
for (const obj of req.body) {
try {
await connection.promise().beginTransaction();
const [result1, fields1] = await connection.promise().query(query1)
const [result2, fields2] = await connection.promise().query(query2);
const [result3, fields3] = await connection.promise().query(query3);
const [result4, fields4] = await connection.promise().query(query4);
await connection.promise().commit();
}
catch (error) {
await connection.promise().rollback();
connection.release();
res.status(400).send(error);
return;
}
}
res.status(200).send('Transaction Complete');
}
});
});

How to make an async function with mysql in node.js

I try to store the result of my mysql request into and async function (to make something after storing my result) but it's returning undefined.. I don't know why
function hh () {
connection.query('SELECT * FROM `rounds` ', function (error, results, fields) {
if (error) throw error;
// console.log(results)
return results
});
}
async function run() {
connection.connect();
let deter = await hh();
console.log(deter)
connection.end();
}
run();
You're not returning a promise... Try with this code, it could help...
function hh () {
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM `rounds` ', function (error, results, fields) {
if (error) return reject(error);
// console.log(results)
resolve(results)
});
});
}
async function run() {
connection.connect();
let deter = await hh();
console.log(deter)
connection.end();
}
run();

MySQL NodeJS .then() s not a function

Can't I use promise for nodeJS mysql query?
// My DB settings
const db = require('../util/database');
db.query(sqlQuery, [param1, param2])
.then(result => {
console.log(result);
})
.catch(err => {
throw err;
});
It is returning: TypeError: db.query(...).then is not a function
You mentioned in the comments that you want logic after the query block to be awaited, without placing that logic inside of the callback. By wrapping the method with a Promise, you can do that as such:
try {
const result = await new Promise((resolve, reject) => {
db.query(sqlQuery, (error, results, fields) => {
if (error) return reject(error);
return resolve(results);
});
});
//do stuff with result
} catch (err) {
//query threw an error
}
Something like this should work
function runQuery(sqlQuery){
return new Promise(function (resolve, reject) {
db.query(sqlQuery, function(error, results, fields) {
if (error) reject(error);
else resolve(results);
});
});
}
// test
runQuery(sqlQuery)
.then(function(results) {
console.log(results)
})
.catch(function(error) {
throw error;
});
mysql package does not support promise. We can use then only a function call returns a promise.You can use mysql2 which has inbuilt support for Promise. It will also make your code more readable. From mysql2 docs:
async function main() {
// get the client
const mysql = require('mysql2/promise');
// create the connection
const connection = await mysql.createConnection({host:'localhost',
user: 'root', database: 'test'});
// query database
const [rows, fields] = await connection.execute(query);
// rows hold the result
}
I would aslo recommend you to learn about callbacks, promise and async-await

Nodejs with Mysql Database Return value

I have the following code. I am relative new to nodejs &js
I want to get values in 1. log but i get undefined.
Only 2. log is outputed to the log.
I read nodeJS return value from callback and
https://github.com/felixge/node-mysql but there is no example about return value.
I donot know how to use return statement with the given example in node-mysql page.
exports.location_internal = function (req, res) {
var r = getExternalLocation(2);
// 1. log
console.log(r);
res.send( r);
}
var getExternalLocation = function (id) {
pool.getConnection(function(err, connection){
if(err) throw err;
var response = {};
connection.query( "select * from external_geo_units where geo_unit_id = "+id, function(err, rows){
if(err) throw err;
response.data= rows;
// 2. log
console.log(response);
return response;
});
connection.release();
});
};
It's asynchronous, so you have to pass in a callback to get the value when it's ready. Example:
exports.location_internal = function(req, res, next) {
getExternalLocation(2, function(err, rows) {
if (err)
return next(err);
console.log(rows);
res.send(rows);
});
};
function getExternalLocation(id, cb) {
pool.getConnection(function(err, conn) {
if (err)
return cb(err);
conn.query("select * from external_geo_units where geo_unit_id = ?",
[id],
function(err, rows) {
conn.release();
cb(err, rows);
});
});
}

Node.js, Express and Mysql. How is correct way

What i'am trying to achieve is to make DB query inside closure. Return data and then send stuff to user. I understand that best practice is to use database pooling. Problem is that query is not sync.
Simplified code:
server.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
mysql = require('mysql');
app.set('DB:pool', mysql.createPool(process.env.DATABASE_URL));
var myClosure = require('./closure.js')(app));
app.get('/somepage', function(req, res) {
var data = myClosure.myquery();
res.send(data);
});
app.get('/anotherpage', function(req, res) {
var data = myClosure.myquery();
res.send(data);
});
app.listen(3000);
closure.js
function myClosure(app) {
var pool = app.get('DB:pool');
return {
myquery: function(inp) {
pool.getConnection(function(err, db) {
if (err) throw err;
db.query('SELECT * FROM table', function(err, rows, fields) {
if (err) throw err;
data = rows[0]
db.release();
});
});
return data;
}
};
}
module.exports = myClosure;
In examples i found all DB related stuff were made in route callback and response was sent in query callback. But way i'm trying to do it is not working as myquery returns undefined because sql query is not done there.
So what is correct way to handle querys ?
Make your query-function handle a callback too:
// server.js
app.get('/somepage', function(req, res) {
myClosure.myquery(function(err, data) {
// TODO: handle error...
res.send(data);
});
});
// closure.js
...
myquery: function(callback) {
pool.getConnection(function(err, db) {
if (err) return callback(err);
db.query('SELECT * FROM table', function(err, rows, fields) {
// release connection before we return anything, otherwise it
// won't be put back into the pool...
db.release();
if (err) return callback(err);
callback(null, rows[0]);
});
});
}
(I left out the inp argument because that didn't seem to be used)