Wait for MySQL query execution in node,js - mysql

I am using mysql in node.js. And there is a nested query in it. But it does not wait for inner query to complete. I don't understand call backs nd other function. My code is like.
exports._getItems=function(req,res){
let categoryId=req.query.categoryPost;
console.log(categoryId+"re")
con.query("SELECT item_id FROM shop_products where category_id =?",[categoryId], function (err, result, fields) {
if (err) throw res.status(403);
else
{
console.log("jhcsdcshd");
var parsedResult = JSON.parse(JSON.stringify(result));
let itemsData="";
for (var i = 0; i < parsedResult.length; i++)
{
let item_id=parsedResult[i].item_id;
console.log("Item_id is"+item_id)
con.query("SELECT id,modelNo FROM items where id =?",[item_id], function async(err1, result1, fields1,callback) {
if (err1) throw res.status(403);
else
{
var parsedResult1=JSON.parse(JSON.stringify(result1));
console.log(parsedResult1)
itemsData=itemsData+parsedResult1[0].id;
console.log("dddd"+itemsData);
if(i=parsedResult.length)
{
console.log("here");
console.log("Data"+itemsData)
res.status(200).send(itemsData);
}
}
});
console.log("ppppppp"+itemsData);
}
}
});
}
I just want that if anyone can tell me that exactly how i let do the wait for inner query execution according to my code . It is very appreciated if anyone can help me. Thanks

You can not call mysql query inside for loop you have to wait for execution. Here is your solutions
exports._getItems = function (req, res) {
let categoryId = req.query.categoryPost;
console.log(categoryId + "re")
con.query("SELECT item_id FROM shop_products where category_id =?", [categoryId], function (err, result, fields) {
if (err) throw res.status(403);
else {
console.log("jhcsdcshd");
var parsedResult = JSON.parse(JSON.stringify(result));
let itemsData = "";
var promises = [];
for (var i = 0; i < parsedResult.length; i++) {
let item_id = parsedResult[i].item_id;
console.log("Item_id is" + item_id);
promises.push(runQuery(con, item_id))
}
Promise.all(promises)
.then((data) => {
for (var i = 0; i < data.length; i++) {
var parsedResult1 = JSON.parse(JSON.stringify(data[i]));
console.log(parsedResult1)
itemsData = itemsData + parsedResult1[0].id;
console.log("dddd" + itemsData);
if (i = parsedResult.length) {
console.log("here");
console.log("Data" + itemsData)
res.status(200).send(itemsData);
}
}
})
.catch((error) => {
throw res.status(403);
})
}
})
}
function runQuery(con, item_id) {
return new Promise((resolve, reject) => {
con.query("SELECT id,modelNo FROM items where id =?", [item_id], function (err1, result1) {
if (err1) {
reject(err1);
} else {
resolve(JSON.parse(JSON.stringify(result1)));
}
})
});
}

Related

Node JS callbacks in a while loop

I have a MySQL database with the table id which stores all the unique id's generated till date, using nanoid module. I have implemented the following code to generate a unique id which is not in the table.
//sql library
const mysql = require('mysql');
const sql_obj = require(__dirname + '/../secret/mysql.json');
//nanoid library
const { customAlphabet } = require('nanoid');
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const nanoid = customAlphabet(alphabet, 30);
function uniqueid(){
let found = 0;
let conn = mysql.createConnection(sql_obj);
while (found === 0){
let id = nanoid();
conn.connect(function(err){
if (err){
found = 2;
}
else{
conn.query("SELECT * FROM id WHERE value = " + mysql.escape(id),function(err,result,fields){
if (err){
found = 2;
}
else{
if (result.length === 0){
found = 1;
}
}
})
}
})
}
if (found === 2){
return {error: 1,ret: null};
}
else if (found === 1){
return {error: 0,ret: id};
}
}
console.log(uniqueid());
I knew, my implementation is wrong. Because callbacks are asynchronous in nature, the while loop never ends and hence I got the error JavaScript heap out of memory. I went through many articles in the web to sort this out, but couldn't. The main problem is that the function uniqueid should return some value, because, I am calling it from other JavaScript file.
Thanks for any help
I think best way to prevent this is using async/await.
I promisified your mySql connection. And you can send your query and values to the function.
//sql library
const mysql = require('mysql');
const sql_obj = require(__dirname + '/../secret/mysql.json');
//nanoid library
const { customAlphabet } = require('nanoid');
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const nanoid = customAlphabet(alphabet, 30);
let db = (query, values = null) => {
return new Promise((resolve, reject) => {
let conn = mysql.createConnection(sql_obj);
conn.connect(function (err) {
if (err) {
reject(err);
}
else {
conn.query(query + values, function (err, result, fields) {
if (err) {
reject(err);
return;
}
else {
if (result.length === 0) {
resolve();
}
}
})
}
})
})
}
async function uniqueid() {
while (found === 0) {
let id = nanoid();
try {
await db("SELECT * FROM id WHERE value =", mysql.escape(id));
return { error: 0, ret: id };
} catch (error) {
return { error: 1, ret: null };
}
}
}
console.log(uniqueid());

Adding bulk data to mysql database

I have a console program where the user scans in serial numbers, and those serial numbers get added to a database.
const mysql = require('mysql2');
const read = require('readline-sync');
const conn = new mysql.createConnection(config);
conn.connect(
function(err){
if(err){
throw err;
}
else{
console.log("Connection Established");
while(1){
var sn = read.question('Scan in serial number: ');
conn.query('INSERT INTO test (serial) VALUES (?);',
[sn], function(err, results, fields){
if (err){
throw err;
}
else{
console.log("Added stuff");
}
});
}
}
}
);
When the code runs it successfully connects to the database but queries the database. It continually prompts for user input.
Alternatively, I tried storing serial numbers in an array and then loops through it adding each element, like this.
const mysql = require('mysql2');
const read = require('readline-sync');
var array = [];
var sn = " ";
while (1) {
sn = read.question('Scan in serial number, or enter "done" if finished scanning');
if (sn == "done") {
break;
}
array.push(sn);
}
conn.connect(
function (err) {
if (err) {
throw err;
}
else {
console.log("Connection Established");
array.forEach(function (sn) {
conn.query('INSERT INTO test (serial) VALUES (?);',
[sn], function (err, results, fields) {
if (err) {
throw err;
}
else {
console.log("Added stuff");
}
});
});
}
}
);
In this case, it works inconsistently. Sometimes it works fine, and other times it fails to connect and throws a timeout error. Is there a better way to accomplish this and/or am I doing something wrong?
var promises = []
function dbOp(value) {
return new Promise(function(resolve, reject) {
conn.query('INSERT INTO test (serial) VALUES (?);',
[value], function (err, results, fields) {
if (err) {
return reject(err)
}
else {
console.log("Added stuff");
resolve(results)
}
}
}
conn.connect(function(err){
if(err){
throw err;
}
else{
for (i = 0; i < array.length; ++i) {
promises.push(dbOp(array[i]));
}
}
});
Promise.all(promises)
.then((results) => {
console.log("done", results);
})
.catch((e) => {
console.log(e)
});
This might be caused by short idle timeout setting in your mysql server. client.connect() is pretty much a no-op in mysql2, it connects immediately when you call mysql.createConnection(). You can change order to establish connection only after all data is collected:
const mysql = require('mysql2');
const read = require('readline-sync');
var array = [];
var sn = ' ';
while (1) {
sn = read.question('Scan in serial number, or enter "done" if finished scanning');
if (sn == 'done') {
const conn = mysql.createConnection(config);
array.forEach(function(sn) {
conn.query('INSERT INTO test (serial) VALUES (?);', [sn], function(err, results, fields) {
if (err) {
throw err;
} else {
console.log('Added stuff');
}
});
});
}
array.push(sn);
}

Nodejs for loop with MySQL insert not functioning as expected

When I trying to Insert some data and process the result using "for Loop", iteration only complete in last cycle.
const sql4 = "insert into core_crm_job_task set ?";
for(var m = 0; req.body.jobTasks.length > m; m++){
console.log('a'+m);
let jobTask = {
ID_JOB_REGISTRY : registryId,
ID_TASK_CODE : jobCode+' '+req.body.jobTasks[m].task_code_suffix,
TASK_TYPE : req.body.jobTasks[m].task_type,
TASK_QTY : req.body.jobTasks[m].task_qty,
TASK_INSTRUMENT : req.body.jobTasks[m].task_instrument,
TASK_INSTRUMENT_ID : req.body.jobTasks[m].task_instrument_id,
REMARK : req.body.jobTasks[m].task_remark,
IS_ACTIVE: 1,
CREATED_BY: 1,
CREATED_DATE: getCurrentTime()
};
connection.query(sql4,jobTask, (err, result) => {
if (err){
console.log('b'+m);
connection.release();
}
else{
console.log('c'+m);
//some process here
}
})
}
Below shows sample output when I used an array with 3 elements.
The log with letter 'c' only print in last element. Other elements didn't complete the iteration.
a0
a1
a2
c2
But I need to do some process after each insert query. In this case it is impossible.
Please suggest some solution!
You can you can use async.eachAsync Ref
So it will execute one by one, you will get expected result
const sql4 = "insert into core_crm_job_task set ?";
async.each(req.body.jobTasks,function(obj,callback){
let jobTask = {
ID_JOB_REGISTRY : registryId,
ID_TASK_CODE : jobCode+' '+obj.task_code_suffix,
TASK_TYPE : obj.task_type,
};
connection.query(sql4,jobTask, (err, result) => {
if (err){
callback(err);
}
callback(null);
})
});
Problem solved! :)
Just Replaced for loop variable type to "let"
for(var m = 0; req.body.jobTasks.length > m; m++)
to
for(let m = 0; req.body.jobTasks.length > m; m++)
addEmojies: function (request, callback) {
//getting the inputs
var questions = request.body.question;
//if questions contains only one
if (!Array.isArray(questions)) {
questions = que = [request.body.question];
}
const mysqlConnection = mysqlPool(function (err, connection) {
connection.beginTransaction(function (err) {
if (err) {
connection.release();
if (err) { throw err; }
}
//loop trough the questions
for (var q = 0; q < questions.length; q++) {
//setting up data object for update category
var mainQuestionValues = {
CAMPAIGN_ID: questions[q].campaign_id,
MAIN_QUESTION_TITLE: questions[q].question,
CREATED_BY: session.userdata.user_id,
HAS_SUB_QUESTIONS:0,
IS_ACTIVE: 1
};
const sql = 'INSERT INTO main_question SET ?';
connection.query(sql, mainQuestionValues, function (err, result) {
if (err) {
if (err) { throw err; }
connection.release();
connection.rollback(function () {
return callback(false);
});
}
connection.commit(function (err) {
if (err) {
connection.release();
logger.error(err);
connection.rollback(function () {
return callback(false);
});
}
connection.release();
return callback(true);
});
});
}
});
});
},

nodejs mysql variable access after promise

I'm beginner into nodeJS world and i try to connect a mysql database. I first select a team (equipe) and after that i have to select all the members of this team.
Finally, i want to construct an array with my teams and the members (in the lesEquipes var). When the code comes to the 3rd then, my var is null ! WHY please ?
Here is my code :
class Database {
constructor() {
this.connection = mysql.createConnection({
host: "192.x.x.x",
user: "john",
password: "mypass",
database: "mybase"
});
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.connection.query(sql, args, (err, result, fields) => {
if (err) return reject(err);
resolve (result);
});
});
}
close() {
return new Promise((resolve, reject) => {
this.connection.end(err => {
if (err) return reject (err);
resolve();
});
});
}
}
var database = new Database();
.............
app.post('/visu',function(req,res){
//console.log(nodedump(req.params.mdp));
//console.log(req.body);
// codage en dur de l'authentification
if((req.body.email == "john#gmail.com") && (req.body.mdp == "password")){
var leUser = "administrateur";
let lesEquipes = new Array();
let test = 'Toto';
database.query("select * from equipe order by id")
.then( result => {
for (var i = 0; i < result.length; i++) {
let courante = new Array();
let nomEquipe = result[i].nomEquipe;
let idEquipe = result[i].id;
courante[0] = result[i];
var sql2 = "select * from participant where equipe = " + result[i].id;
//console.log(sql2);
database.query(sql2)
.then(result2 => {
console.log("Membres de l'équipe : " + nomEquipe);
courante[1] = result2;
console.log("COURANTE 2 "+ JSON.stringify(courante));
lesEquipes[idEquipe] = courante;
let test = 'AUTRE CHOSE';
/*
console.log("QUERY 2 "+ JSON.stringify(result2));
for (var j = 0; j < result2.length; j++) {
participant = result2[j].nom;
console.log(participant);
}
*/
//res.render('visuEquipes.ejs', { user:leUser, equipes:lesEquipes});
//console.log("Contenu "+ JSON.stringify(lesEquipes));
return ""; //database.query(sql3);
});
}
console.log("Contenu "+ JSON.stringify(test));
console.log("Contenu "+ JSON.stringify(lesEquipes));
}).then(result3 =>{
console.log("result 3 : "+result3);
console.log("Contenu "+ JSON.stringify(test));
**// THIS VAR IS NULL NULL NULL lesEquipes
console.log("Contenu "+ JSON.stringify(lesEquipes));**
res.render('visuEquipes.ejs', { user:leUser, equipes : lesEquipes});
}).catch((err) => {
console.log(err);
database.close();
});
The problem is that you are executing asynchronous code inside a loop.
for (var i = 0; i < result.length; i++) {
/**/
database.query(sql2).then(result2 => {
/**/
});
}
So in .then(result3 =>{ the variable lesEquipes is very likely to have not been initialized.
You have to wait for all the promises to resolve. You can easly add an array of promises.
const promises = [];
for (var i = 0; i < result.length; i++) {
promises.push(database.query(sql2).then(result2 => {/*...*/}));
}
return Promise.all(promises);
Or you can use async-p library to iterate the array, or better you can use ES7 async-await constructs.

How can I execute the SQL query first then the rest of the code?

static listFunc() {
let funclist = [];
const queryList = "SELECT * FROM func";
mysqlModule.queryDB(database, queryList, (err, result) => {
console.log(result[0].id);
if (err) {
res.status(500).json({
"status_code": 500,
"status_message": "internal server error"
});
} else {
for (var i = 0; i < result.length; i++) {
let func = {
'id': result[i].id,
'psw': result[i].senha,
'nome': result[i].nome,
'DoB': result[i].dataNascimento,
'sexo': result[i].genero,
'morada': result[i].morada,
'permissoes': result[i].permissoes
}
funclist.push(func);
}
return funclist;
}
});
}
I created a function to give me all the workers from my DataBase and then store them inside funclist array.
The problem is the for loop is running before the query.
How can I run the loop only after query as finished?
Pass a callback function into listFunc:
static listFunc(callback){...}
Instead of returning the list just invoke the callback:
callback(funclist);
static listFunc() {
return new Promise((resolve,reject)=>{
let funclist = [];
mysqlModule.queryDB(database,"SELECT * FROM func", (err, result) => {
if (err) throw err;
result.forEach((result) => {
let func = {
'id': result.id,
'psw': result.senha,
'nome': result.nome,
'DoB': result.dataNascimento,
'sexo': result.genero,
'morada': result.morada,
'permissoes': result.permissoes
}
funclist.push(func);
});
resolve(funclist);
});
});
}
First i changed the "for" loop to a "each" loop and i used the promise to give me the data only after i get the query and the loop finished.
function clistFunc(req, res){
Func.listFunc().then((data)=>{
res.render('admin/adminListFunc', { funclist: data});
console.log(data);
}).catch(()=>{
console.log('Error');
});
}
Then i just rendered the jade only after my listFunc() return the pretended data.