Node Js asyncronic mysql query - mysql

I´m trying to do an asynchronous query in NodeJS but keep getting undefined as a result, my code is:
async function Nuevo_Parametro() {
sqlStr = "select * from Parametros limit 10";
conCasos.query(sqlStr, function(err, Resultado, fields) {
if (err) throw err;
return Resultado;
});
}
Nuevo_Parametro().then(Resultado => {
console.log(Resultado);
});
What am I doing wrong?
Thanks in advance

you're mixing callback styles with Promises. The mysql function does not return a Promise, so you can't concatenate it. It uses a callback style - meaning the "async" part is executed in that callback you provide as a parameter.
What you need to do is wrap it up with a Promise and return that. Something along the lines of the following
function Nuevo_Parametro() {
sqlStr="select * from Parametros limit 10"
return new Promise((resolve, reject) => {
conCasos.query(sqlStr, function(err, Resultado,fields) {
if (err) {
return reject(err)
};
resolve(Resultado);
})
})
}
Nuevo_Parametro().then(Resultado => {
console.log(Resultado)
})
Here we return a promise we're creating, and in the callback query offers, I'm resolving it. I kept the variables and property names as they are for simplicity.
If you're going to use extensively the queries, perhaps it might be tedious to be newing promises everytime, so as it's mentioned in this github ticket you can use a wrapper like this one
or maybe use the native promisify utility as this comment states
const fn = util.promisify(connection.query).bind(connection);
const rows = await fn('SELECT col1, col2 FROM users WHERE email = ?', [email]);

Related

How to implement a map nested MySQL query in Node that populates a property of each element

I've searched this so many ways and can't seem to get a solution that works for me - perhaps because I'm new to JS and the callback "hell" as I've seen it described.
I first run a query that returns a list of results ("FailTypes"), then I want to iterate over each item in the list and add a property ("FailTypeAreaScores") which itself requires another query. I figured the map function would be the best to do this.
Here's the calling function, 1st query:
static async getFailTypes(eq, callback) {
const sql = 'CALL getFailTypes(?)';
db.query(sql, eq, async (err, rows) => {
let result = Object.values(JSON.parse(JSON.stringify(rows)));
let fts = await Promise.all(result[0].map(async ft => {
const newFt = await getFailTypeAreaScores(ft, (err, data) => {return data})
return newFt }));
if (err){
console.log(err.message);
} else {
callback(null, fts);
};
});
};
Here's the nested query:
async function getFailTypeAreaScores(ft, callback){
const sql = 'CALL getFailTypeAreaScores(?);';
db.query(sql, ft.ID, async(err, rows) =>{
let result = Object.values(JSON.parse(JSON.stringify(rows)));
if (err){
console.log(err.message);
} else {
ft.ftas = result[0];
callback(null, ft);
}
});
};
I've tried various methods of promises and callbacks and nothing seems to work. Right now, I'm getting the data back as expected at the {return data} and if I replace that with a {console.log(data)} I can see the new ft with the added property in the console.
However, it doesn't seem to get out of that function and back up to the map to replace the original ft.
So, my resulting callback(null, fts) just returns a list of null.

Node mysql select result can't be stored into variable

I'm working on a script that insert and reads information on a mysql database. I've done the first step which is create registers on the database and works but I'm having issues reading the data out from the database.
I have a main.ts that call all the functions that performs the select/insert statements and a dao.ts with all the funtions that interact with the database.
This is the code where I call the function:
const vehiclesDB = select('SELECT * FROM vehicles', con);
console.log(vehiclesDB);
This is always returning undefined.
And this is the code that performs the sql statement:
export const select = (statement: string, dbConnection: any) => {
const results = dbConnection.query(statement, function (err, res, fields) {
if (err) throw err;
return res;
});
return results;
}
If I do a console.log on the res variable inside the select function I can see the result rows. I've tryed setting the results variable as return from the select function but what I can see on the main.ts then is the db connection details.
This is the library I'm working with to interact with mysql through node:
https://github.com/mysqljs/mysql
You are not returning any value from the function select. Also I don't think you can use both await and a callback for the query method. If the library only allows callbacks, wrap everything inside a Promise:
export const select = (statement: string, dbConnection: any) => {
return new Promise((resolve, reject) => {
dbConnection.query(statement, function (err, res, fields) {
if (err) return reject(err);
return resolve(res);
});
})
}
If the library allows the usage of Promises, you may want to try this:
export const select = (statement: string, dbConnection: any) => {
return dbConnection.query(statement);
}
Also since you marked the function as aync it returns a Promise. You have to use await or .then() when calling the function.
const vehiclesDB = await select('SELECT * FROM vehicles', con);

Why can't I use a local variable after a SQL query in Node.js?

I have to select all tags available in the database, so I could use them in my function, but I can't use the variable after I assigned a value to the variable in the callback function of the query, why?
Code which is not working:
let tags = [];
db.query(
`select * from tags`,
(err, results) => {
tags = results;
}
)
console.log(tags);
return;
However this works:
let tags = [];
db.query(
`select * from tags`,
(err, results) => {
tags = results;
console.log(tags);
}
)
return;
but why? I want to use the variable tags after that query again, but somehow the value assigned to it is destroyed after the query. What would I have to change?
Javascript is asynchronous language, db.query is a network call which will be asynchronous, so if you want to use the response of the query it has to be called after the db.query is executed.
In the first case console.log(tags); runs before db.query is executed
and you are getting undefined response.
In the second case console.log(tags); runs after db.query is executed thats why you are getting the response from the query.
You use this using Promise:
async function queryExec() {
let tags = await promiseQuery(`select * from tags`);
console.log(tags);
return tags;
}
function promiseQuery(query) {
return new Promise((resolve, reject) => {
db.query(query, (err, results) => {
if (err) {
return reject(err);
}
resolve(results);
})
})
}
With async/await:
async function queryExec() {
let tags = await db.query(`select * from tags`);
console.log(tags);
return tags;
}
Query is an async function, so the value hasnt returned by the time you try to print it.
within the callback function however, you already have the return value you expect.
If you need it to run synchronously you could await the query function, and have the value in hand.
If you set your function be async then you will be able to await the result.
something like:
const foo = async () => {
let tags = [];
tags = await db.query(
`select * from tags`
);
console.log(tags);
return;
}

Return MySql results from JavaScript Class

I am having an issue returning results from a Express JS model. I think my problem is a lack of understanding of callbacks and JS Classes. I just can't seem to make it work.
I have the following code.
From the server.js I have this route:
app.get('/api/v1/loralocations/:id', LoraLocation.getOne);
Which calls the Controller action below
getOne(req, res) {
const lora_location = LoraLocationModel.findOne(req.params.id);
if (!lora_location) {
return res.status(404).send({'message': 'LoraLocation not found'});
}
return res.status(200).send(lora_location);
},
.
.
.
Model
var pool = require('./mysqlDb.js');
import moment from 'moment';
class LoraLocation {
/**
* class constructor
* #param {object} data
*/
constructor() {
}
findOne(id) {
var sql = ('SELECT test FROM Test WHERE id = ?');
pool.query(sql, [id], function (err, results, fields) {
if (err) return err;
console.log(results); //works
return results; //nope
});
}
The console.log returns the results, but nothing is returned to the controller. I have gone through a number of posts but can't seem to find a solution. I think maybe I need a callback in the controller also?
Would this be a fairly standard pattern for a simple API project?
Thanks
You are using callback incorrectly.
either you can use async/await which is a good option or if you want to stick with callbacks then you need to return callback function.
controllers
const lora_location = LoraLocationModel.findOne(req.params.id, function (err, data) => {
});
in the model it should be
findOne(id, cb) {
var sql = ('SELECT test FROM Test WHERE id = ?');
pool.query(sql, [id], function (err, results, fields) {
if (err) cb(err, []);
console.log(results); //works
cb(null, results);
});
}
you can get more details for callbacks in this link
https://medium.com/better-programming/callbacks-in-node-js-how-why-when-ac293f0403ca

async function with mysql query won't return query results node.js

I have a function that queries a mysql database with a select query. This is all inside an async function. The query keeps telling me on the return line that it cannot find the variable "rollStatus".
async function PullRollStatus(){
return new Promise((resolve,reject)=>{
var sql = `SELECT * FROM brawlid${brawlID}`
con.query(sql, (error, rows, fields) => {
var rollStatus= []
for (var i in rows) {
rollStatus.push(rows[i].Bakuganrolled)
}
})
console.log(rollStatus)
return rollStatus
})
}
var rolledcheck = await PullRollStatus();
console.log(rolledcheck)
I've never used new Promise before, as async functions are still kind of new to me. I have tried this without the "return new Promise" line and with it, both giving the same result. I have referenced this
async and await on MySQL call in node js and I'm still getting some problems or it might be confusing me more, I don't know. Any help is greatly appreciated. Thanks in advance!
I would have to know a bit more about the database and the value of brawlID, but you don't use return with promises instead you use resolve and reject, also, you are returning a promise, do you don't use async. Here is an edited example. Note I use mysql.format to pass the variable into the query, this will safeguard against code injection.
Also, I would think you would be using a where statement, unless you have a table for each brawlID, but it would make for sense if brawlID is a column in the table. I changed the function to take the value of brawID passed parameter instead of referencing a global variable.
const mysql = require("mysql2/promise");
const mysqlconfig = {
host: "localhost",
user: "youruser",
password: "yourpassword"
database: "yourdb"
multipleStatements: true
};
const con = mysql.createConnection(msqlconfig);
function to (promise) {
return promise
.then(val => [null, val])
.catch(err => [err]);
}
function PullRollStatus(brawlID){
return new Promise((resolve,reject)=>{
let sql = `SELECT * FROM brawlid WHERE brawlID=?`;
mysql.format(sql,brawlID);
con.query(sql, (error, rows, fields) => {
if (error) {
reject(error);
} else {
let rollStatus = [];
for (let row of rows) {
rollStatus.push(row.Bakuganrolled)
}
console.log(rollStatus);
resolve(rollStatus);
}
});
});
}
let brawlIDtoCheck = 1;
let [err,rolledcheck] = await to(PullRollStatus(brawlIDtoCheck));
if (err) {
console.log("encountered err",err);
}
console.log(rolledcheck)