Node JS MySQL wait for results - mysql

I'm quite new to Node JS, and I'm trying to build an API based on MySQL.
In one of my routers I'm trying to inject an insert query and based on it, get the new generated task id from mysql.
The problem is that the second query is not waiting for the response and sometimes I'm getting an error because taskId variable is undefined because it still didn't get the results from the first query.
the problematic variable that is not getting it's value correctly is taskId.
I'm attaching my code for your review, thanks for your help!
As requested: I'm attaching my required moudle as well:
const dotenv = require('dotenv');
const mysql = require('mysql');
dotenv.config();
var connection = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_TABLE,
port: process.env.DB_PORT
});
module.exports = connection;
router.post('/new', auth, async (req, res) => {
const uid = req.body.uid;
const taskName = req.body.taskName;
const description = req.body.description;
const createdDate = req.body.createdDate;
const estimatedDate = req.body.estimatedDate;
const status = req.body.status;
let taskId = '';
addTaskQuery = `INSERT INTO task (title,description,status) VALUES ('${taskName}','${description}','${status}')`;
findTaskIdQuery = `SELECT id FROM task WHERE title = '${taskName}'`;
try {
// Injecting into task table
await connection.query(addTaskQuery, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
})
// Getting the new inserted task id
await connection.query(findTaskIdQuery, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
taskId = JSON.stringify(results[0].id);
})
// Injecting into havetask table
await connection.query(`INSERT INTO havetask (id,userId,taskId) VALUES (${taskId},${uid},${taskId})`, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
})
}
catch(err) {
console.log(err);
return res.status(401).json({ msg: 'An error occured while tried to add task'});
}
})

The mysql package you use does not support Promises (=== it doesn't do async / await). So your await statements don't wait, they just fall through.
You need to try a package that handles async / await. This one might do the trick.

Related

Node.js executing mysql query after receiving message from mqtt broker

I have a node.js file that subscribes to a topic and upon receiving a published message scans a local mysql db for the most recent entry in a variable named "command". Command values will trigger various responses, but I have left this portion out since my issue is before this.
My mysql query appears to be giving me errors. I am trying to look for the most recent entry of the command column and assign the value to a var command. I thought this code would do the trick:
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) throw err;
});
console.log(result);
var command = result[1];
console.log(command);
But I am getting the following response which seems to indicate an error in the mysql query:
user#server.domain [bin]# node motorlistener.js
Connected to MYSQL!
Connected to Broker!
{"pulse":1}
1
/home/user/etc/domain/bin/motorlistener.js:62
console.log(result);
^
ReferenceError: result is not defined
at MqttClient.<anonymous> (/home/user/etc/domain/bin/motorlistener.js:62:17)
at MqttClient.emit (events.js:314:20)
at MqttClient._handlePublish (/home/user/node_modules/mqtt/lib/client.js:1277:12)
at MqttClient._handlePacket (/home/user/node_modules/mqtt/lib/client.js:410:12)
at work (/home/user/node_modules/mqtt/lib/client.js:321:12)
at Writable.writable._write (/home/user/node_modules/mqtt/lib/client.js:335:5)
at doWrite (/home/user/node_modules/readable-stream/lib/_stream_writable.js:409:139)
at writeOrBuffer (/home/user/node_modules/readable-stream/lib/_stream_writable.js:398:5)
at Writable.write (/home/user/node_modules/readable-stream/lib/_stream_writable.js:307:11)
at TLSSocket.ondata (_stream_readable.js:718:22)
The full code is below, but does anyone know what is causing this error?
////////////////////////////////////////////////////////////////////////////////
//setup
var mqtt = require('mqtt'); //for client use
const fs = require('fs');
var caFile = fs.readFileSync("/home/user/etc/domain/bin/ca.crt");
var topic = "heartbeat";
var mysql = require('mysql');
var con = mysql.createConnection({
host : 'localhost',
user : 'myuser',
password : 'mypass',
database : 'mydb'
});
var options={
port:8883,
clientId:"yo",
username:"myuser2",
password:"mypassw",
protocol: 'mqtts',
clean:true,
rejectUnauthorized: false,
retain:false,
ca:caFile
};
var client = mqtt.connect("http://dns.org",options);
//mqtt connection dialog
client.on("connect",function(){
console.log("Connected to Broker!");
client.subscribe(topic, {qos:1});
});
//mqtt connection handle errors
client.on("error",function(error){
console.log("Broker Connection Error");
process.exit(1);
});
//database connection
con.connect(function(err) {
if (err) throw err;
console.log("Connected to MYSQL!");
});
//handle incoming messages from broker
client.on('message',function(topic, message, packet){
var raw = ""+message;
console.log(raw);
var obj = JSON.parse(raw);
var pulse = obj.pulse;
console.log(pulse);
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) throw err;
});
console.log(result);
var command = result[1];
console.log(command);
if (command == 1) {
console.log("command=1");
}
else {
console.log("command not equal to 0");
}
});
I am getting the following response which seems to indicate an error in the mysql query
That's not an error in your MySQL query. It's a null reference error because you're trying to use result outside the callback.
Changing your code to this will work:
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) {
throw err;
}
// access result inside the callback
console.log(result);
var command = result[0];
console.log(command);
});
Depending on your environment you may be able to re-write your code using promises and async/await to reduce the nested scopes.
To do so, you'd need to turn your callback into a promise and then you can await it, like so:
let sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
// 1 -- we turn the query into a promise
const queryPromise = new Promise((resolve, reject) => {
con.query(sql, function (queryError, queryResult) {
if (queryError) {
reject(queryError);
}
resolve(queryResult);
});
});
try {
// 2 -- we can now await the promise; note the await
let result = await queryPromise;
// 3 -- now we can use the result as if it executed synchronously
console.log(result);
let command = result[0];
console.log(command);
} catch(err) {
// we can catch query errors and handle them here
}
Putting it all together, you should be able to change the on message event handler to an async function in order to take advantage of the async/await pattern as shown above:
client.on('message', async function(topic, message, packet) {
/* .. you can use await here .. */
});
All above code from #Mike Dinescu works perfectly fine. Just dont forget on the end to close the connection!
Else the runner will hangs after tests have finished.
the full solution:
async function mySqlConnect(dbquery) {
const conn = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'test',
password: 'test',
database: 'test'
}, { debug: true });
// 1 -- we turn the query into a promise
const queryPromise = new Promise((resolve, reject) => {
conn.query(dbquery, function (queryError, queryResult) {
if (queryError) {
reject(queryError);
}
resolve(queryResult);
});
});
try {
// 2 -- we can now await the promise; note the await
let result = await queryPromise;
// 3 -- now we can use the result as if it executed synchronously
//console.log(result);
let command = await result[0];
//console.log(command);
return command;
} catch(err) {
}
finally{
conn.end(function(err) {
if (err) {
return console.log('error:' + err.message);
}
//console.log('Close the database connection.');
});
}
}

undefined value if no result returned in API Mysql query

I'm working on my first API every and first time every using Node.js.
I have this code which is test code. I'm trying to get a Chemist users name and password from my system.
If the query runs and a row exists, this works fine, however I'm try to get a console log error or even a status result and I can't.
It just dies on the const section because there IS no row.
I have tried moving the declarations under the IF section but that also results in errors!
Thanks for any point in the right direction.
const express = require('express');
const router = express.Router();
var config = require('./../../databaseConfig');
var connection= config.connection;
router.get('/:id',(req,res) => {
connection.query('SELECT * FROM tblChemists WHERE chemistID = ?',[req.params.id],(err,rows,fields)=>{
const chemName = rows[0].chemistName;
const chemPass = rows[0].chemistpass;
if(!err)
console.log(chemName),
console.log(chemPass),
res.status(201).json({
message: 'Chemist Found',
name: chemName,
pass: chemPass
});
else
console.log(err);
})
});
module.exports = router;
You need to check to see if rows has data before trying to access it. You should also look at wrapping everything in a try-catch
router.get('/:id', (req, res) => {
connection.query('SELECT * FROM tblChemists WHERE chemistID = ?', [req.params.id], (err, rows, fields) => {
if (rows && Array.isArray(rows) && rows.length) {
const chemName = rows[0].chemistName
const chemPass = rows[0].chemistpass
} else {
return res.status(500).send('no rows returned')
}
if (!err) {
console.log(chemName),
console.log(chemPass),
res.status(201).json({
message: 'Chemist Found',
name: chemName,
pass: chemPass
})
} else {
console.log(err)
}
})
})

Node callback returns mysql result but i cant print to the user with actions on google for dialogflow

I created an intent to get user information based on the ID he provides as param. Using a mysql module i can process the query and get the result. With a callback i can get the result to the main function but the agent ignores once i pass to a conv.ask(). What am i doing wrong?
This is my first script with node. I tried declaring pesquisar_aluno() in a variable so i could use in the main function but it retuns null.
const express = require('express');
const bodyParser = require('body-parser')
const mysql = require('mysql')
const {
dialogflow,
SignIn,
SimpleResponse
} = require('actions-on-google')
app.intent('pesquisar.alunos', (conv, params) => {
const aluno = params.aluno
conv.ask('Vamos pesquisar')
pesquisar_aluno(aluno,function(result){
var resposta = result
console.log(resposta) // returns the result
conv.ask(resposta) // ignores it
})
console.log(resposta) // returns undefined
})
function pesquisar_aluno(aluno,callback)
{
var connection = mysql.createConnection({
host : process.env.MYSQL_HOST,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PASS,
database : process.env.MYSQL_DB
})
connection.connect()
var query = `SELECT * FROM aluno WHERE id_aluno = "${aluno}"`
connection.query(query, function (error, results, fields)
{
if(error) throw error
var usuario = `RA =>${results[0].id_aluno} Nome => ${results[0].nome}`
if(callback) return callback(usuario)
})
}
Expect conv.ask(resposta) to print the result to the user but its not printing anything
Edit: Changed to promises. It worked!Thanks to Nick Felker and Prisoner
app.intent('pesquisar.alunos', (conv, params) => {
const aluno = params.aluno
conv.ask('Vamos pesquisar')
let nome = pesquisar_aluno_promise(aluno).then(function(results) {
return results[0].nome
}).catch((err) => setImmediate(() => { throw err; }))
return nome.then(function(result){
conv.ask(result)
})
})
async function pesquisar_aluno_promise(aluno)
{
return new Promise(function (resolve,reject) {
var connection = mysql.createConnection({
host : process.env.MYSQL_HOST,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PASS,
database : process.env.MYSQL_DB
})
connection.connect()
var query = `SELECT * FROM aluno WHERE id_aluno = "${aluno}"`
connection.query(query, function (error, results, fields)
{
if (error) {
return reject(error)
}
resolve(results)
})
})
}
As Nick suggested in the comments, you need to use Promises when you are doing asynchronous operations.
Additionally, however, you need to return that Promise from your Intent Handler so the Intent Dispatcher knows to wait for the result before continuing.
In your case, this can just be adding return, so it might look something like this:
return nome.then(function(result){
console.log(result) //works
conv.ask(result) //should work now
})

discord.js/node.js make code wait until sql query returns result

I am working on a discord.js bot, and I'm storing a bunch of information on various servers in a database. The problem is, that the code doesn't wait for the database to return the results. In the current situation, I'm trying to check if the server specific prefix checks out.
I tried using async and await at various places, but those didn't work. If I could, I'd rather not use .then(), because I don't really want to put all the commands inside a .then().
const { Client, Attachment, RichEmbed } = require('discord.js');
const client = new Client();
const mysql = require("mysql");
const config = require("./config.json")
var con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'botdb'
})
client.on("ready", () => {
console.log("I'm ready")
})
client.on("message", message => {
if (message.author.bot) return;
if (message.channel.type === 'dm') return;
let msg = message.content.split(" ");
let command = msg[0];
let prefix;
con.query(`SELECT * FROM serversettings WHERE ServerID = ${message.guild.id}`, (err, rows) => {
if (err) throw err;
prefix = rows[0].Prefix;
console.log(prefix)
})
console.log(`Prefix: ${prefix}, Command: ${command}`)
if (command === `${prefix}examplecommand`) {
//Do something
}
//Other code that uses prefix and command
}
It should log the prefix first, and then the Prefix: ${prefix}, Command: ${command} part, but it does it the other way around, so the examplecommand doesn't work.
Your result is caused by the fact that what's outside your query callback is executed immediately after the call. Keep in mind the mysql module is callback-based.
Possible Solutions
Place the code inside the callback so it's executed when the query is completed.
Wrap the query in a promise and await it.
function getGuild(guildID) {
return new Promise((resolve, reject) => {
con.query(`SELECT * FROM serversettings WHERE ServerID = '${guildID}', (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
}
const [guild] = await getGuild(message.guild.id) // destructuring 'rows' array
.catch(console.error);
console.log(guild.prefix);
Use a Promise-based version of a MySQL wrapper, like promise-mysql. You could use it the same way as the code above, without worrying about coding your own Promises.
const [guild] = await con.query(`SELECT * FROM serversettings WHERE serverID = '${message.guild.id}'`)
.catch(console.error);
console.log(guild.prefix);

rely on the result of a query to run another nodejs mysql

Hey guys I have the following node code and it works fine
import express from 'express';
import connection from '../index.js'
const router = express.Router();
router.get('/allTemplates', function (req, res) {
let queryString="select count(*) as exist from users where userName='bob'";
let query = connection.query(queryString, (error, result) => {
if(error) {throw error;}
res.json(result);
})
});
module.exports = router;
what I want to do is react to this with something like
if(exists==1){error='sorry but that user already exists';} else {
queryString="insert into users (userName, email, address) values('bob', 'emailAddress#email.com', 'address')";
let query = connection.query(queryString, (error, result) => {
if(error) {throw error;}
res.json(result);
})
}
I come from a php background so this is all very new and the async of node freaks me out but I have to use it for my new job. How would I react to a result of one query and run another one based on the outcome.
I put the mysql library in a variable called database and I am using async await to run queries. In the database file I connect to the database and set up my variables like so:
const mysql = require("mysql");
const util = require("util");
const awsConfig = {
host: process.env.RDS_HOST,
user: process.env.RDS_USER,
password: process.env.RDS_PASSWORD,
database: process.env.RDS_DATABASE
};
const connection = mysql.createConnection(awsConfig);
connection.query = util.promisify(connection.query.bind(connection));
connection.end = util.promisify(connection.end.bind(connection));
module.exports = connection;
Than i use async await to run queries and use the results to run or not run others. like so:
let result;
let sqlStatement ="";
result = await database.query(sqlStatement);
let userExists = result[0].exist;
sqlStatement =
"SELECT COUNT(*) AS exist FROM user where userName=" +
database.escape(req.body.userName);
if(userExists==0){
result = await database.query("INSERT INTO user SET ?", [req.body]);
}
hope this helps someone else