Node mysql select result can't be stored into variable - mysql

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

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.

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

Node Js asyncronic mysql query

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

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)

Node.js - Use asynchronous function to get a return value in a synchronous way without callbacks

I have a function to retrieve a list of UserID's from a mysql database.
function GetUsers(callback) {
UpdateLogFile('Function Call: GetUsers()')
var users = []
Database.execute( connectionStr,
database => database.query('select UserID from Users')
.then( rows => {
for (let i = 0; i < rows.length; i++){
users.push(rows[i].UserID)
}
return callback(users)
})
).catch( err => {
console.log(err)
})
}
For Reference:
Database class which came from here
const mysql = require( 'mysql' )
class Database {
constructor( config ) {
this.connection = mysql.createConnection( config )
}
query( sql, args ) {
return new Promise( ( resolve, reject ) => {
this.connection.query( sql, args, ( err, rows ) => {
if ( err )
return reject( err )
resolve( rows )
})
})
}
close() {
return new Promise( ( resolve, reject ) => {
this.connection.end( err => {
if ( err )
return reject( err )
resolve()
})
})
}
}
Database.execute = function( config, callback ) {
const database = new Database( config )
return callback( database ).then(
result => database.close().then( () => result ),
err => database.close().then( () => { throw err } )
)
}
After hours of learning about promises and callbacks, I was finally able to get GetUsers() to at least work and return what I'm looking for. However, I seem to only be able to use it as such:
GetUsers(function(result){
// Do something with result
})
But I would really like to be able to have a traditional return statement in the function so that I could use it like this: var users = GetUsers(). I have seen posts saying that this is impossible due to the nature of asynchronous functions but I am still hopeful since I would really like to be able to avoid callback hell. I tried the code below but "users" just results as undefined after execution. So, my main goal is to be able to get the return value from GetUsers() without chaining callbacks together since I have other functions that behave similarly. Is this possible?
var users
GetUsers(function(result){
users = result
})
console.log(users)
This is a very confusing topic, and it took me a while to really understand why what you are asking simply is not possible (at least, in the exact way you are asking). For the examples I will using python Django and Node.js to compare.
Sync
def synchronous():
print('foo') //this will always print first
print('bar')
def getUsers():
with connection.cursor() as cursor:
cursor.execute('SELECT * FROM USERS') //this query is executed
users = cursor.fetchall()
print('foo') //this doesn't trigger until your server gets a response from the db, and users is defined
print(users)
Async
function asynchronous() {
console.log('foo'); //this will also always print first
console.log('bar');
}
function getUsers() {
var connection = mysql.createConnection(config);
connection.query('SELECT * FROM USERS', function(error, users) { //this is a "callback"
console.log(users); //this will print
//everything inside of here will be postponed until your server gets a response from the db
});
console.log('foo') //this will print before the console.log above
console.log(users); //this will print undefined
//this is executed before the query results are in and will be undefined since the "users" object doesn't exist yet.
}
A callback is simply the function that your server is supposed to run once you get a response. We typically use the actual word "callback" like this:
function getUsers(callback) {
var connection = mysql.createConnection(config);
connection.query('SELECT * FROM USERS', function(error, users) {
if (error) throw error; //always do your error handling on the same page as your query. Its much cleaner that way
callback(users) //server asks what to do with the "users" object you requested
});
}
Now on somewhere else on your server:
getUsers(function(users) {// the callback gets called here
console.log(users); //do what you want with users here
});
The getUsers function takes some other function (ie a callback) as its argument and executes that function after you perform your query. If you want to do the same thing without using the word "callback", you can use an await/async function like fsociety, or you explicitly write out your code and not make functions that take other functions as their arguments.
This is functionality identical to the code from above:
var connection = mysql.createConnection(config);
connection.query('SELECT * FROM USERS', function(error, users) {
if (error) throw error;
console.log(users);
});
Callback hell is inevitable, but it really Isn't too bad once you get the hang of it.
Use an async-await function instead.
async function GetUsers(callback) {
try {
UpdateLogFile('Function Call: GetUsers()')
var users = []
let rows = await Database.execute( connectionStr,
database => database.query('select UserID from Users')
for (let i = 0; i < rows.length; i++){
users.push(rows[i].UserID)
}
return callback(users)
} catch(err) {
console.log(err)
}
}
Hope this helps!