async await is not executing functions sequentially in express nodejs - node.js

I want to run 3 database query then render the 3 result objects to view, so I used async await to run queries first but seems its not waiting/working, always sending null objects to view before running queries. Cant find where I went wrong, I am using nodejs 12.16.1, not sure if its es6 supporting issue or sth else.
var express = require('express');
var router = express.Router();
var reviewModel = require.main.require('./models/review-model');
var propertyModel = require.main.require('./models/property-model');
router.get('/', async function(req, res){
try{
req.cookies['username'] == null ? loginCookie = null : loginCookie = req.cookies['username'];
var getPromoteInfo = await propertyModel.getPromoteInfo(function(result){
if(result!=null) return result;
});
var getPromoteReview = await reviewModel.getPromoteReview(function(result2){
if(result2!=null) return result2;
});
var getLatest3reviews = await reviewModel.getLatest3reviews(function(result3){
if(result3!=null) return result3;
});
res.render('index', {property:getPromoteInfo, rating:getPromoteReview, testimonials:getLatest3reviews, loginCookie});
}
catch(err){console.log(err);}
});
module.exports = router;
Model code:
var db = require('./db');
module.exports = {
getPromoteInfo: function(callback){
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
callback(result);
}else{
callback(null);
}
});
}
}

You're using await on a function that does not return a Promise resulting in an undefined value. So in order for async/await to work, you could rewrite getPromoteInfo as follows:
var db = require('./db');
module.exports = {
getPromoteInfo: function(){
return new Promise( (resolve, reject) => {
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
resolve(result);
}else{
// you can decide whether to reject or not if no records were found
reject();
}
});
});
}
}
In your express-handler you can then simply await this function call, without passing a callback:
const getPromoteInfo = await propertyModel.getPromoteInfo();
Note that you can check if your db-client/library supports promises out of the box - then you would not have to wrap your functions manually in a promise.

Related

How to return data from a method that uses async functions?

I'm pretty new to using Express.js and I have an issue returning the data from the database query. The goal is to get user info from the table as JSON inside userController but only thing I get is undefined. I tried many different things but can't get my head around how to return the value from the method.
db.js
const mysql = require('mysql2');
var con = mysql.createPool({
//db data here
});
module.exports = con;
userController.js
var User = require("../models/userModel");
exports.registerUser = function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(u1.getInfo());
}
}
userModel.js
const db = require('../config/db');
module.exports = class User{
//constructor here
getInfo(){
try{
var query = "SELECT * FROM users";
db.query(query, function(err, data){
return JSON.stringify(data);
});
}
catch(err){
return err;
}
}
}
You are getting undefined because the query need to wait the answer, and when you call getInfo(), the return JSON.stringify(data); are only execute when the query have the data.
You can use promise warper, because you need to wait to the database response. To use promises mysql2 have this package: const mysql = require('mysql2/promise');
Make your getInfo() function asynchronous
async getInfo(){
try{
const res = await db.execute('SELECT * FROM users');
return res;
}
catch(err){
return err;
}
}
Then you can call the function with await:
exports.registerUser = async function(req, res){
if(req.method == 'POST'){
var username = req.body.username;
var email = req.body.email;
//doing checks
var u1 = new User(username, email);
console.log(await u1.getInfo());
}
I cant test the code now, but it should work

why does my async function returns undefine while working with mysql2?

I've been trying non-stop to work on this query for my datatables front end.
this is my config.js
var config = {
host : 'localhost',
user : 'root',
password : '',
database : 'ef45db'
}
module.exports = config;
this is the function I want to work with async (wait for the query to return the table's columns name)
async function getColumnNames()
{
try{
aColumns = [];
await connection.query('SHOW COLUMNS FROM '+sTable,
function selectCb(err, results, fields){
console.log("entro a getColumnNames");
if(err){
console.log(err);
}
for(var i in results)
{
aColumns.push(results[i]['Field']);
}
connection.end();
});
}catch (e){
console.log(e);
}
}
and this is the controller code to execute that function:
var mysql = require('mysql2');
var config = require('.././database/config');
var connection = mysql.createConnection(config);
var sIndexColumn = '*';
var sTable = 'users';
var aColumns = [];
module.exports = {
getInfo : async function(req,res,next)
{
var request = req.query;
(async () => await getColumnNames());
console.log(aColumns);
}
I'm trying to get the column's name so I can work with datatable's filtering for backend, since node is async this query was getting executed, but the value was undefined (and still is), I've read hundreds of post regarding promises, bluebird and async methods and trying to make this work, the last I've read a lot thats the best and I choosed it because the code seems cleaner. Any ideas whats happening?
For getColumnNames(), you shouldn't use await because connection.query doesn't return promise. It is a callback function.
However, we can make getColumnNames to return promise.
function getColumnNames() {
const aColumns = [];
return new Promise((resolve, reject) => {
connection.query('SHOW COLUMNS FROM ' + sTable,
function selectCb(err, results, fields) {
console.log("entro a getColumnNames");
if (err) {
console.log(err);
reject(err); // if error happens, reject
}
for (var i in results) {
aColumns.push(results[i]['Field']);
}
connection.end();
resolve(aColumns); // resolve with our database columns
});
});
}
and for your controller we can use async await since getColumnNames returns promise as in
module.exports = {
getInfo: async function (req, res, next) {
var request = req.query;
const aColumns = await getColumnNames();
console.log(aColumns);
}
}
Let me know if it works for you.

Getting empty array in nodejs

I am posting value But I am getting empty array . I know its node asynchronous problem . But I don't know how do i solve this. I have refer this following link:
How do I return the response from an asynchronous call?
But I could not able to understand . Kindly help me to understand promises and how do i use that in my code.
router.post('/inspection_list', function (req, res) {
var id = req.body.project_id;
console.log(id)
// res.send("ok")
db.inspection.findOne({'_id':id},(err,response)=>{
if(err){
console.log("error");
}
else{
console.log("Data")
var inspection = [];
var data = response.inspection_data;
var f = data.map(function (item) {
var fielduser = item.fielduser_id
db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)},(err,user)=>{
console.log(user.owner_name);
console.log(item.inspection_name)
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
})
});
console.log(inspection) // Here am getting empty value
// setTimeout(function(){ console.log(inspection) }, 5000); my timeout code
}
})
});
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; i++){
var item = data[i]
var fielduser = item.fielduser_id
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
}
catch(err){
throw err
}
})
This uses async and await, you can use it if you are using node version >=7.6
Also note the following:
router.post('/inspection_list', async function (req, res)
Handling each error seperately
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
}
catch(err){
// handle error here
throw err
}
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; var item = data[i]
var fielduser = item.fielduser_id
try{
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
}
catch(err){
// handle error
}
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
})
Using mongoose would be the easy way out, it returns Promises for all query and save functions, so you'd simply do:
YourModel.findOne({params}).then(() => {...})
If you're unable to do that, in your case, a 'promisified' example would be:
var findAndFillArray = (project_id) => new Promise((resolve) => {
.... your previous code here ....
inspection.push({inspection_name:item.inspection_name,field_user_name :
user.owner_name})
if (data.length === inspection.length){ // Or some other preferred condition
resolve(inspection);
}
})
Then you'd call this function after you get the id, like any other function:
var id = req.body.project_id;
findAndFillArray(id).then((inspection_array) => {
res.send(inspection_array) // Or whatever
})
Now, map and all list functions are synchronous in JS, are you sure the error is due to that?

Gather multiple functions output on single route call and render to html in nodejs

Newbie to nodejs,trying to execute multiple functions output to html using nodejs,express and mysql as backend.Need to execute 20 functions on single routing call to combine the output of 20 functions and render as json to html.
My app.js function
var express = require('express');
var router = express.Router();
var path = require('path');
var app = express();
var todo = require('./modules/first');
var todo1 = require('./modules/second');
var connection = require('./connection');
connection.init();
app.get('/', function(req,res,next) {
Promise.all([todo.class1.getUsrCnt(),todo.class1.getTotlAmt(),todo.class1.getTotlOrdrCnt(),todo.class1.getTotlCntRcds(),todo.class1.getTotlScsRcds(),todo.class1.getTotlFailRcds(),todo.class1.getTotlAmtRcds()])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
app.get('/second', function(req,res,next) {
Promise.all([todo1.class2.getUsr........])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
var server = app.listen(8183, function(){
console.log('Server listening on port '+ server.address().port)
});
My todo.js is
var connection = require('../connection');
var data = {},obj={};
var d = new Date();
var month = d.getMonth() + 1;
var year = d.getFullYear();
obj.getUsrCnt = function getUsrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query1, function(err, result) {
con.release();
data.usrs_cnt = result[0].some;
})
});
}
obj.getTotlAmt = function getTotlAmt(callback) {
connection.acquire(function(err, con) {
con.query(query2, function(err, result) {
con.release();
data.total_amt = result[0].some1;
})
});
}
obj.getTotlOrdrCnt = function getTotlOrdrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query3, function(err, result) {
con.release();
data.total_orders = result[0].some2;
})
});
}
.
.
. functions go on
exports.class1 = obj;
Getting undefined in the promise all and unable to render to the html file.
Not sure about the code you wrote, but as I understand you want to call all the functions, get all the results and return back to the user?
so you can use many libraries that waits for several calls for example, promise based:
Promise.all([todo.getUsrCnt('dontcare'), todo.getTotlAmt('dontcate')])
.then(function(allData) {
// All data available here in the order it was called.
});
as for your updated code, you are not returning the data as promises, you assigning it to the local variable.
this is how your methods should look:
obj.getUsrCnt = function getUsrCnt(callback) {
var promise = new Promise(function(resolve, reject) {
connection.acquire(function(err, con) {
if(err) {
return reject(err);
}
con.query(query1, function(err, result) {
con.release();
resolve(result[0].some);
})
});
});
return promise;
}
as you can see here, I am creating a new promise and returning it in the main function.
Inside the new promise I have 2 methods: "resolve", "reject"
one is for the data and one is for errors.
so when you use the promise like this:
returnedPromise.then(function(data) {
//this data is what we got from resolve
}).catch(function(err) {
//this err is what we got from reject
});
you can see that a promise can or resolved or rejected,
do this to all the methods, and then you start seeing data

Nodejs MySQL connection timeout

When I run the application, It shows me Database is connected!
db.js
var mysql = require('mysql');
var settings = require('./config');
var db;
var exports = {};
exports.connectdb = function () {
db = mysql.createConnection(settings.Database);
db.connect(function(err){
console.log('connecting');
if(!err) {
console.log('Database is connected!');
return db;
} else {
console.log('Error connecting database!'+err);
return null;
}
});
};
module.exports = exports;
but when i am trying to connect DB from user.js it shows me connection is null / TypeError: Cannot read property 'query' of undefined.
code block from user.js
var exports = {};
var dbcon = require('../config/db.js');
var dbconn = dbcon.connectdb();
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
var dbconn = dbcon.connectdb();
if ( dbconn == null ) console.log('still nul');
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
return null;
}
});
};
module.exports = exports;
Node.js is asynchronous by nature. You are trying to use it in a synchronous fashion. To make this work, you must use the callback pattern. Below is an example:
db.js
var mysql = require('mysql');
var settings = require('./config');
var exports = {};
exports.connectdb = function (callback) {
var db = mysql.createConnection(settings.Database);
db.connect(function(err){
callback(err,db);
});
};
module.exports = exports;
user.js
var exports = {};
var dbcon = require('../config/db.js');
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
dbcon.connectdb(function(err, dbconn){
if ( err) //handle error
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
}
});
});
};
module.exports = exports;
From the code above you can see how the connectdb function accepts a function callback. When the database is connected the code will execute that callback to send the results. In the user.js file, you can now pass a callback function and use the results it gives you (the db). You can find more info about Node.js' asynchronous nature here. Basically, asynchronous code uses callbacks and synchronous code uses return statements. Returning values from asynchronous functions will most always yield null results as asynchronous callbacks will always fire "sometime" after the function is called.

Resources