Nodejs Mysql asynchronous - mysql

I'm trying to return my users list from my Mysql database through this endpoint.
The problem is that it return "undefined".
Do you know how to solv this?
Thx in advance :)
app.get("/users", async (req, res) => {
users = await query_my_users_from_db()
// Got "users = undefined" here
console.log(users)
return JSON.stringify(users)
})
async function query_my_users_from_db() {
var users = await db.query("SELECT * FROM `users`", function (err, result) {
if (err) throw err
users = Object.values(JSON.parse(JSON.stringify(result)))
return users
})
}

Since db.query is callback based, you should change your code into:
function query_my_users_from_db(callback) {
db.query("SELECT * FROM `users`", callback)
}
remove all the async\await since you are not using any promises!
then define your callback
const usersHandler = (err, result) => {
... do what you want with your users ...
}
and use it like this:
query_my_users_from_db(usersHandler)
Another option is to use some promise-based wrapper package for MySQL, there is plenty or use node util.promisify() (https://www.geeksforgeeks.org/node-js-util-promisify-method/) and then use async\await and remove the callback altogether.
Hope that it helps

I used this and it's working like a charm.
db.promise = (sql, params) => {
return new Promise((resolve, reject) => {
db.query(sql, params, (err, result) => {
if (err) {
reject(new Error())
} else {
resolve(result)
}
})
})
}
async function connection(query) {
const result = await db.promise(query)
return result
}
app.get("/users", async (req, res) => {
users = await connection("SELECT * FROM `users`")
return users
})

Related

Mongoose updating and fetching in the same request

I have the following mongoose "update" path:
app.put('/update', async (req, res) => {
const newTaskName = req.body.todoName
const newDays = req.body.days
const id = req.body.id
try {
await TodoModel.findById(id, async (err, updatedTodo) => {
updatedTodo.todoName = newTaskName
updatedTodo.daysToDo = newDays
await updatedTodo.save()
res.send("updated")
})
} catch(err) {
console.log(err)
}
})
Separately I have a path that returns all data from the Mongo table:
app.get('/read', async (req, res) => {
TodoModel.find({}, (err, result) => {
if (err) {
res.send(err)
}
res.send(result)
})
})
How can I both update and send back the full updated list within the response?
Separate question, not necessary to answer, but would be nice - perhaps this approach is all wrong? some background:
In my MERN app I am calling to add an item to a list and then want to immediately render the updated list as currently read from the database, since I don't want to assume the insertion was successful
I tried using some asynchronous workarounds with no luck
Fixed!
Upon further inspection of Mongoose documentation, I found that by using the findOneAndUpdate method instead of findById, I am able to utilize a callback that will return the updated item:
app.put('/update', async (req, res) => {
const id = req.body.id
let updateSet = req.body
delete updateSet.id
try {
ShoppingModel.findOneAndUpdate({ _id: id }, { $set: updateSet }, { new: true }, (err, doc) => {
if (err) return console.log(err)
res.send(doc)
})
} catch (err) {
console.log(err)
}
})

Return mysql query result using Promise

I'm currently a little confused as to how to properly wait for the promise to finish before returning the result from a query
Here is my current code:
const getLeaderboardValues = async () => {
const SQLConnection = await getSQLConnection();
return new Promise((resolve, reject) => {
SQLConnection.query(getValuesSQLQuery, (err, result) => {
if (err) { reject(err) }
return resolve(result);
});
SQLConnection.end()
})
}
const runtime = () => {
getLeaderboardValues().then((result) => {
console.log(result);
})
}
The code above does log the correct results while debbugging, i believe this is because i'm giving the code more time to render with the breakpoints, however when running normally i get undefined
I believe the SQLConnection.end() line is executing before the query is returned, given it is outside the query statement.
The below may solve your issue, however I do not recommend opening a connection and closing it on every request in production systems.
const getLeaderboardValues = async () => {
const SQLConnection = await getSQLConnection();
return new Promise((resolve, reject) => {
SQLConnection.query(getValuesSQLQuery, (err, result) => {
if (err) {
reject(err)
return SQLConnection.end()
}
SQLConnection.end()
return resolve(result);
});
})
}
const runtime = () => {
getLeaderboardValues().then((result) => {
console.log(result);
})
}

Returning undefined from mySQL

I know the database is connecting with the code as, when i console.log(res) with the code below it is returning the correct data,
const orm={
selectAll(){
connection.query('SELECT * FROM burgers', (err,res) => {
if (err) throw err;
console.log(res)
return res;
});
},
Yet when i console.log(burgers) from this function in the code below it is returning an undefined
app.get(`/`, function (req, res) {
const burgers = orm.selectAll();
console.log(burgers)
res.render(`index`, burgers);
});
I understand this may be a very simple answer but i personally just cannot work it out any help is welcomed.
selectAll is using a callback style method inside it. You can not get the response syncronously. You need to either pass the callback to selectAll or change it to use promise like this
function selectAll() {
return new Promise((reoslve, reject) => {
connection.query("SELECT * FROM burgers", (err, res) => {
if (err) {
reject(err);
}
reoslve(res);
});
});
}
You can then use it like this
app.get(`/`, function async (req, res) {
const burgers = await selectAll();
console.log(burgers)
res.render(`index`, burgers);
});
Your selectAll method will not return any value.
query get an lambda callback function as second parameter AND query is asyncron
One way is to return an Promise from selectAll
const orm = {
selectAll(callback) {
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM burgers', (err, res) => {
if (err) {
reject(err);
} else {
resolve(res)
}
})
})
},
Than you can get your result:
app.get(`/`, function (req, res) {
orm.selectAll().then( burgers => {
console.log(burgers)
res.render(`index`, burgers);
});
});

How to return result of db from a nested functions in nodejs

I want the result on other file but not getting how to return it
function getUsers(){
console.log("Fetching all user data");
const connection = getConnection();
const sql = "SELECT * FROM users";
var result = connection.query(sql,(err, rows, fields) =>{
if(err){
console.log("Failed to get users data");
res.sendStatus(500);
throw err;
}
console.log("Fetched Users Successfully");
return rows;
})
return result;
}
This is a standard asynchronous function problem.
return rows will not assign rows to the result variable. Second argument of query() function is a callback function and it indicates a block of code that will be executed after rows are fetched. It means that result of the query is only visible inside callback block.
You can fix it in 2 ways:
Write all your code that uses SQL result inside callback function block (You can call another function at that point and pass result as argument for example).
This method is simpler if you are new to javascript programming. I see that you want to use function getUsers() in another place. If you choose this approach, best way would probably be to pass a callback to the getUsers() function and then invoke it in the callback of the query() method.
Example:
getUsers(callback){
const connection = getConnection();
const sql = "SELECT * FROM users";
connection.query(sql,(err, rows, fields) => callback(rows))
}
mainFunction(req,res){
getUsers(doSomethingWithUsers)
}
doSomethingWithUsers(users){
...
}
This is of course, oversimplified pattern, but the idea should be clear.
Research about promises and how they handle async functions. This will require you to "wrap" you function body into Promise object type.
They will allow you to write something like this:
mainFunction(){
getUsers().then(result => ....);
// or even
const users = await getUsers();
}
EDIT:
To wrap "return value of promise", or as we say "to resolve a promise", you can wrap function the following way:
function getUsers(){
console.log("Fetching all user data");
const connection = getConnection();
const sql = "SELECT * FROM users";
return new Promise( (resolve,reject) => {
var result = connection.query(sql,(err, rows, fields) =>{
if(err){
// this will cause promise to "fail"
reject(err);
}
console.log("Fetched Users Successfully");
// this will tell javascript that promise is finished
// and rows are accesable in then()
resolve(rows);
})
})
}
function mainFunction(){
const result = getUsers()
.then(rows =>{/** this will happen if resolve(rows) is called */})
.catch(error => {/** this will be executed if reject(err) happens
*/});
}
// or... (Try/Catch is required since "await" silently fails
async function asyncMainFunction(){
try{
const rows = await getUsers();
// You can use rows from resolve() here;
}catch(error){
// here, reject is called
}
}
Here is a link where you can read more about promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You are not getting the result because the code is asynchronous. So, you have to use async/await to get the result. Your code should look like this:-
async function getUsers(){
console.log("Fetching all user data");
const connection = await getConnection();
const sql = "SELECT * FROM users";
try {
var result = await connection.query(sql);
console.log("Fetched Users Successfully");
return result;
} catch (err) {
console.log("Failed to get users data");
res.sendStatus(500);
throw err;
}
}
Finally, call this function like this:-
var output = await getUsers();
But make sure that you call this line in an async function.
Hope this helps!
create file for function : getUsers.js
module.exports = async getUsers(){
const connection = getConnection();
const sql = "SELECT * FROM users";
var myPromise = () => {
return new Promise((resolve, reject) => {
connection.query(sql, query.params, function (error, results, fields) {
error ? reject(error) : resolve(results);
})
});
}
var result = await (myPromise());
return result;
}
require this file and call function :
var getUsers = require('..path to getUsers');
var data = getUsers().then((data)=>{
}).catch((error)=>{
console.log('error',error)
return error;
});
using callback :
or using callback function :
module.exports = function getUsers(callback){
const connection = getConnection();
const sql = "SELECT * FROM users";
connection.query(sql, query.params, function (error, results, fields) {
if(error){ callback(error,null)}
if(!error && results){
callback(null,results)
}
});
}
require file :
var getUsers = require('..path to getUsers');
call it this way :
getUsers(err,data)=>{
if(err){
return res.send(err);
}
if(!err && data){
return res.send(data);
}
}
function getUsers(callback) {
console.log("Fetching all user data");
const connection = getConnection();
const sql = "SELECT * FROM users";
connection.query(sql, (err, rows, fields) => {
if (err) {
console.log("Failed to get users data");
res.sendStatus(500);
callback(err, null);
}
console.log("Fetched Users Successfully");
callback(null, rows)
})
}
// USE ABOVE FUNCTION AS BELOW...
getUsers(function(err, rows) {
if(err){
console.error(err);
}
console.log(rows);
})

var is undefined if using var keyword node

Building a small MVC. When I'm receiving results back from my model, the variable that I'm using to send to my view is undefined if I use the "var" keyword. If I don't use the keyword the object comes through just fine. What is happening?
Controller
const homeModel = require('../models/homeModel.js');
exports.index = function(req, res){
homeModel.getAllStores(function (err, res) {
if (err) return err;
stores = res; // Works
var stores = res // Undefined
})
console.log(stores);
res.render('home', {stores: stores});
}
Here is the Model
const db = require('../db.js');
exports.getAllStores = function(done) {
db.query('select * from stores;', (err, rows) => {
if (err) return done(err);
let resultJson = JSON.stringify(rows);
resultJson = JSON.parse(resultJson);
return done(null, resultJson);
})
}
You need to move the declaration of stores to the function enclosing homeModel.getAllStores(). This is because JavaScript is function (lexically) scoped, so a variable will be scoped to the nearest enclosing function. You can read more about how variables that are declared using var work on MDN.
In Node.js, if you don't provide the var keyword before your variable then it is globally scoped to the module in which it is running, this is why console.log(stores) works when you use stores = res and not var stores = res.
To properly scope your variable using var, just move your declaration to the function being exported.
Additionally, your console.log() and res.render() calls are occurring before the callback function for homeModel.getAllStores() is executed and setting stores = res. Since res.render() and console.log() will only work as expected within the callback to homeModel.getAllStores() you can simplify index() and the callback to homeModel.getAllStores().
const homeModel = require('../models/homeModel.js')
exports.index = (req, res) => {
return homeModel.getAllStores((err, stores) => {
if (err) {
throw err
}
console.log(stores)
return res.render('home', {stores})
})
}
You could also use util.promisify() and async/await to write this a little more straightforward.
const {promisify} = require('util')
const getAllStores = promisify(require('../models/homeModel').getAllStores)
const index = async (req, res) => {
let stores
try {
stores = await getAllStores()
} catch (err) {
console.error(err)
return res.sendStatus(500)
}
return res.render('home', {stores})
}
module.exports = {index}
Here is an example with Promise.all() waiting for the results from multiple queries with a hypothetical UserModel with getAllUsers() that works identically to homeModel.getAllStores() but queries a users table.
const {promisify} = require('util')
const getAllUsers = promisify(require('../models/userModel').getAllUsers)
const getAllStores = promisify(require('../models/homeModel').getAllStores)
const index = async (req, res) => {
let queryResults
try {
queryResults = await Promise.all([getAllStores, getAllUsers])
} catch (err) {
console.error(err)
return res.sendStatus(500)
}
let [stores, users] = queryResults
return res.render('home', {stores, users})
}
module.exports = {index}