Struggling to use async await within for loops with nodejs - node.js

I am trying to use multiple functions within a for loop but, one is returning undefined (or not waiting?)
Code is as below:
var arrNew = [];
var id = [];
var get1 = [];
var get2 = [];
var get3 = [];
var res = [];
var get4 = [];
for (j = 0; j < arrNew.length; j++) {
id[j] = arrNew[j];
get1[j] = await get1Fun(context, id[j]);
if (get1[j] !== false) {
get2[j] = await get2Fun(context, get1[j]);
context.log(get2[j]);
if (get2[j].length) {
get3[j] = await get3Fun(context, get2[j]);
if (get3[j] !== false && get3[j].status == 200) {
res[j] = get3[j].result;
get4[j] = await get4Fun(context, id[j], res[j]);
context.log(get4[j])
}
}
}
}
async function get1Fun(context, id) {
const querySpec = {
query: `SELECT * FROM r where r.id = "${id}"`,
};
const { resources } = await client.database(databaseId).container(containerId).items.query(querySpec).fetchAll();
if (resources.length == 1) {
return resources[0];
} else if (!resources.length) {
return false;
}
}
function get2Fun(context, getInt) {
return new Promise((resolve, reject) => {
var msg = []
// do for loop stuff with getInt and push stuff into msg
context.log(msg)
resolve(msg);
});
}
The code works up until this point where get2Fun either returns undefined or if (get2[j].length) does not wait for await get2Fun.
Can someone clarify what is going wrong please?
I have tried with async function and without the promise.
The reason I have the arrays as below is because if I structured the function as var get1 = await get1Fun(context, id) then the for loop would stop after 1 or 2 items and not do every item in arrNew.
Thanks in advance.
EDIT:
Also tried the below but the for loop stops after 1 loop (presumably an issue with each loop redefining a variable?):
for (j = 0; j < arrNew.length; j++) {
var id = arrNew[j];
var get1 = await get1Fun(context, id);
if (get1 !== false) {
var get2 = await get2Fun(context, get1);
context.log(get2);
if (get2.length) {
var get3 = await get3Fun(context, get2);
if (get3 !== false && get3.status == 200) {
var res = get3.result;
var get4 = await get4Fun(context, id, res);
context.log(get4)
}
}
}
}
async function get1Fun(context, id) {
const querySpec = {
query: `SELECT * FROM r where r.id = "${id}"`,
};
const { resources } = await client.database(databaseId).container(containerId).items.query(querySpec).fetchAll();
if (resources.length == 1) {
return resources[0];
} else if (!resources.length) {
return false;
}
}
async function get2Fun(context, getInt) {
var msg = []
// do for loop stuff with getInt and push stuff into msg
context.log(msg)
return msg;
}

Related

why nested async/await doesn't work as intended?

I'm learning NodeJs and having some problems using async/ await. I'm using Firebase database to read/write data. Here what i'm doing. (full function in case you need it).
async getImport(reqData: any): Promise<any> {
const username = 'kdat0310';
const db = admin.database();
const userRef = db.ref('/user');
const importRef = db.ref('/import');
const refAuthentication = db.ref('/Authentication');
const keyList = [];
const providerKey = [];
const khoList = [];
let index = 0;
const providerList = [];
const isValid = await refAuthentication.once('value', function (snapshot) {
for (const val of Object.values(snapshot.val())) {
if (
Object(val).username === Object(reqData).username &&
Object(val).token === Object(reqData).token
) {
return true;
}
}
return false;
});
if (isValid) {
await userRef.once('value', function (snapshot) {
for (const value of Object.values(snapshot.val())) {
if (value) {
if (Object(value).username == username) {
for (const val of Object(value).workAt) {
if (val) khoList.push(val.khoId);
}
}
}
}
});
const typeAndColorKey = [];
const typeAndColorValue = [];
const typeAndColorRef = db.ref('/TypeAndColor');
await typeAndColorRef.once('value', function (snapshot) {
let count = 0;
for (const key in snapshot.val()) {
typeAndColorKey.push(key);
}
for (const value of snapshot.val()) {
if (value !== undefined && value != null) {
typeAndColorValue.push({
id: typeAndColorKey[count],
type: value.type,
color: value.color,
});
count = count + 1;
}
}
});
const findTypeAndColor = (id: any) => {
for (const value of typeAndColorValue) {
if (id == value.id) {
return { type: value.type, color: value.color };
}
}
};
const userKey = [];
const userList = [];
await userRef.once('value', function (snapshot) {
let count = 0;
for (const key in snapshot.val()) {
userKey.push(key);
}
for (const value of Object(snapshot.val())) {
if (value != undefined && value != null) {
userList.push({
id: userKey[count],
name: Object(value).name,
});
count++;
}
}
});
const findUserName = (userId: any) => {
const returnValue = '';
for (const value of userList) {
if (userId == Object(value).id) {
return Object(value).name;
}
}
};
const importList = [];
await importRef.once('value', async function (snapshot) {
const importKey = [];
const cloneArr = snapshot.val().map((item: any) => {
return item;
});
for (const key in snapshot.val()) {
importKey.push(key);
}
let countTemp = 0;
for (const value of Object.values(cloneArr)) {
const goodsKeyList = [];
let count = 0;
if (khoList.indexOf(Object(value).warehouseId) !== -1) {
const listGoodsList = [];
if (Object(value).listGoods) {
for (const key in Object(value).listGoods) {
goodsKeyList.push(key);
}
const refListGoods = db.ref(
'/import/' + importKey[countTemp] + '/listGoods',
);
await refListGoods.once('value', function (snapshot) {
let item: any;
for (item of Object.values(snapshot.val())) {
if (item) {
const tempItem = item.filter((n: any) => n);
listGoodsList.push({
typeAndColor: findTypeAndColor(goodsKeyList[count]),
listGoods: tempItem,
number: tempItem.length,
});
}
count++;
}
});
}
console.log('test 1', listGoodsList);
if (listGoodsList !== []) {
importList.push({
listGoods: listGoodsList,
driver: Object(value).driver,
userId: Object(value).importEmployee,
name: findUserName(Object(value).importEmployee),
orderId: Object(value).orderId,
warehouseId: Object(value).warehouseId,
time: Object(value).time,
});
}
}
countTemp++;
}
console.log('test 2', importList);
});
return importList;
}
return 'Invalid';
}
The problem show up when it came to await importRef.once When I tried to handle some data and add the Firebase once function "async" and await inside to push the data I need to the array. Then return importList; return nothing. I figure that the await refListGoods.once cause this problems. As i thought, the await inside had done its duty and I can console.log importList inside very well. But I thought that await importRef.once will finish before return too. when I delete await refListGoods.once, the return is fine but I dont get the data I need. Do I need to refactor all code as I do to findTypeAndColor and findUserName above or there's a better way to solve this problem?
If you want to use await on the Promise returned by once, you should not pass a callback function to it.
So instead of:
const isValid = await refAuthentication.once('value', function (snapshot) {
for (const val of Object.values(snapshot.val())) {
if (
Object(val).username === Object(reqData).username &&
Object(val).token === Object(reqData).token
) {
return true;
}
}
return false;
});
Do:
const snapshot = await refAuthentication.once('value');
let isValid = false;
snapshot.forEach((child) => {
const val = child.val();
if (val.username === Object(reqData).username &&
val.token === Object(reqData).token
) {
isValid = true;
}
})

Array push gives empty result node js

I am creating an API for listing trip data with image and pdf base url,
All things are working fine but I can not access the last result array data_to_send out of for loop.
app.js
app.get("/getChallanList/:userId/:role", (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
db.select("trip", "*", `driver_id = '${req.params.userId}'`, (data) => {
for (let i = 0; i < data.data.length; i++) {
site_source = data.data[i].site_from;
site_destination = data.data[i].site_to;
db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf =
base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf =
base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img = base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
}
);
}
console.log(data_to_send); // empty
});
}
}
db.select
let select = (table, column, condition, callback) => {
try {
let sql = "SELECT " + column + " FROM " + table + " WHERE " + condition;
conn.query(sql, (err, results) => {
if (err) {
let data = {
status: 0,
data: sql,
message: "Something went wrong!",
};
callback(data);
} else {
let data = {
status: 1,
data: results,
message: "Success",
};
callback(data);
}
});
} catch (err) {
let data = {
status: 0,
data: err,
message: "In catch",
};
callback(data);
}
};
async await
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
await db.select(
"trip",
"*",
`driver_id = '${req.params.userId}'`,
async (data) => {
// const data_to_send_ = [];
for (let i = 0; i < data.data.length; i++) {
site_source = data.data[i].site_from;
site_destination = data.data[i].site_to;
await db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf =
base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf =
base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img =
base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
}
);
// data_to_send_.push(data_to_send);
}
console.log(data_to_send); // empty
}
);
}
}
this is because of the asynchronous behavior of NodeJs, so you have to plan things accordingly i.e
console.log(1)
db.select(
"trip",
"*",
`driver_id = '${req.params.userId}'`,
async (data) => {
console.log(2)
})
console.log(3)
The output of the above code would be 1 then 3 and then 2 and this is how NodeJs works it does not wait for I/O calls i.e DB query in your case.
Please check how promises work in NodeJs for more details.
Here is how you can accomplish your task:
const challanList = (userData) => {
return new Promise((resolve, reject) => {
const data_to_send = [];
db.select("trip", "*", `driver_id = '${req.params.userId}'`, data => {
for (let i = 0; i < data.data.length; i++) {
const site_source = data.data[i].site_from;
const site_destination = data.data[i].site_to;
db.select("site", "*", `id in ('${site_source}','${site_destination}')`, data_site => {
data.data[i].site_from = data_site.data[0].name;
data.data[i].site_to = data_site.data[1].name;
if (data.data[i].truck_challan_pdf != "") {
data.data[i].truck_challan_pdf = base_url + "truckchallan/" + data.data[i].truck_challan_pdf;
}
if (data.data[i].driver_challan_pdf != "") {
data.data[i].driver_challan_pdf = base_url + "driverchallan/" + data.data[i].driver_challan_pdf;
}
if (data.data[i].preparer_img != "") {
data.data[i].preparer_img = base_url + data.data[i].preparer_img;
}
if (data.data[i].driver_img != "") {
data.data[i].driver_img = base_url + data.data[i].driver_img;
}
data_to_send.push(data.data);
// console.log(data_to_send); // working
});
}
resolve(data_to_send);
});
});
};
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
const challanListResult =await challanList(userData);
console.log(challanListResult);
resp.json(challanListResult);
});
Without knowing what database or ORM you are using it is difficult to answer, but my suspicion is that db.select is an asynchronous method, i.e. it is returning a Promise. If so, the second console log is still seeing the "old" data_to_send.
Try adding an await in front of the first db.select call. (Don't forget the async in front of the callback in second argument of app.get.
Your database is asynchronous so console.log(data_to_send) gets called before the query finished executing. Try adding async before (req, res) in line 1 then await before db.select.
This works for me
app.get("/getChallanList/:userId/:role", async (req, res) => {
const userData = req.params;
let site_source = "";
let site_destination = "";
var site_from_name = "";
const data_to_send = [];
if (userData.role == "D") {
const data = await db.query(
`SELECT * FROM trip WHERE driver_id = '${req.params.userId}'`
);
// console.log(data.length);
// const data_to_send_ = [];
for (let i = 0; i < data.length; i++) {
site_source = data[i].site_from;
site_destination = data[i].site_to;
// cons
const site_data = await db.query(
`SELECT * FROM site WHERE id in ('${site_source}','${site_destination}')`
);
// console.log(site_data);
db.select(
"site",
"*",
`id in ('${site_source}','${site_destination}')`,
(data_site) => {
data[i].site_from = data_site.data[0].name;
data[i].site_to = data_site.data[1].name;
if (data[i].truck_challan_pdf != "") {
data[i].truck_challan_pdf =
base_url + "truckchallan/" + data[i].truck_challan_pdf;
}
if (data[i].driver_challan_pdf != "") {
data[i].driver_challan_pdf =
base_url + "driverchallan/" + data[i].driver_challan_pdf;
}
if (data[i].preparer_img != "") {
data[i].preparer_img = base_url + data[i].preparer_img;
}
if (data[i].driver_img != "") {
data[i].driver_img = base_url + data[i].driver_img;
}
data_to_send.push(data);
// console.log(data.data);
// console.log(data_to_send); // working
}
);
// data_to_send_.push(data_to_send);
}
// console.log(data_to_send);
// console.log(data_to_send);
res.send({ success: 1, data: data, message: "" });
}

Can't return value from async function in Node.js but console prints the values

I am new to node.js and I read a few posts about this problem but still don't understand how to solve it in my case. The correct result is printed out, but I want it to be returned or be stored in a variable. Is this possible?
const values = async () =>
{
const URL = 'http://www.espn.com/sports/tennis/rankings';
const response = await request(URL);
const $ = cheerio.load(response);
let title = $ ('#my-players-table > div.mod-container.mod-table > div.mod-content > table > tbody').text();
var rank = 1;
var count = title.length;
var words = title;
var player = "";
var players = [];
for ( var i = 70; i < count; i++)
{
if(!characterNumber(words[i]) && words[i] != "\n")
{
player += words[i];
}
else
{
if(player != "" && player != '\n')
{
players.push(player);
player = "";
}
}
}
return players;
};
let playersRankings;
const getRankings = async () => {
playersRankings = await values();
console.log(playersRankings);
}
getRankings();

Why doesn't my async function return any result?

I wrote this small program to fetch data. This however is done async. Since I nonetheless need to use the function holeVertreter(kzl) as a function in another module, I'd like to get a return value which I can eventually pass on.
Excuse my spaghetti code (I usually prettify the code when I am done with my task ...).
Credentials are stored in a file and are therefore not found in this file.
I'd like to end up with "vertreter" as a return value.
Thank you in advance.
const node = require("deasync");
const DSB = require('dsbapi');
const tabletojson = require('tabletojson');
const https = require('https');
const cred = require("./vertrCred");
const dsb = new DSB(cred["dsb"]["user"], cred["dsb"]["passw"]); //Sanitized - no Credentials here
//Stackoverflow 2332811
String.prototype.capitalize = function(lower) {
return (lower ? this.toLowerCase() : this).replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
};
function holePlan(kuerzel) {
dsb.fetch()
.then(data => {
const timetables = DSB.findMethodInData('timetable', data);
const tiles = DSB.findMethodInData('tiles', data);
var tilesStr = JSON.stringify(tiles["data"][0]["url"]);
var url = JSON.parse(tilesStr);
https.get(url, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end',() => {
var tableasjson = tabletojson.convert(data);
var erstetab = tableasjson[0];
var zweitetab = tableasjson[1];
var drittetab = tableasjson[2];
var viertetab = tableasjson[3];
var fuenftetab = tableasjson[4];
var sechstetab = tableasjson[5];
var siebtetab = tableasjson[6];
var achtetab = tableasjson[7];
if (typeof kuerzel === "undefined")
{
var regenechse = '(Aaa|Aaa[A-Za-z?]|[A-Za-z?]Aaa)';
}
else {
var name = kuerzel.capitalize(true);
var regenechse = '('+name+'|'+name+'[A-Za-z?]|[A-Za-z?]'+name+')';
}
const regex = new RegExp(regenechse,'g');
var sammel = Object.assign(drittetab,fuenftetab);
var z= 0;
var vertreter = {}
var y = JSON.parse(JSON.stringify(sammel));
for (i=0;i<y.length;i++) {
if (typeof y[i].Vertreter =='undefined') {
}
else {
if(y[i].Vertreter.match(regex))
{
z += 1;
vertreter[z] = y[i];
}
}
}
if (z == 0) {
// console.log("Es gibt nichts zu vertreten");
}
else {
//console.log("Es werden "+z+" Stunden vertreten");
return (vertreter);
} ;
});
})
})
.catch(e => {
// An error occurred :(
console.log(e);
});
}
//Stackoverflow
function warte(promise) {
var done = 0;
var result = null;
promise.then(
function (value) {
done = 1;
result = value;
return (value);
},
function (reason) {
done = 1;
throw reason;
}
);
while (!done)
node.runLoopOnce();
return (result);
}
function holeVertretung(kzl) {
var aufgabe = new Promise((resolve,reject) => {
setTimeout(resolve,1000,holePlan(kzl));
});
var ergebnis = warte(aufgabe);
if (typeof ergebnis === "undefined") {
console.log("Mist");
}
else {
console.log(ergebnis);
}
return ergebnis;
}
holeVertretung("Aaa");
That's not the right way to work with promises. If you do such infinite loop, it beats the whole purpose of using promises. Instead, return value from the promise, and use async-await like this:
function warte(promise) {
var done = 0;
var result = null;
return promise.then(
...
}
async function holeVertretung(kzl) {
var aufgabe = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, holePlan(kzl));
});
var ergebnis = await warte(aufgabe);
...
If async-await does not work for some reason, use then clause:
warte(aufgabe).then(value => {
var ergebnis = value;
});

is there a way to avoid set a timeout

I'm trying to collect all values from a mysql table with all the values of the referenced_table_name for each index of the table.
How avoid set a random time out while waiting for a promise
To collect the expected information i need to set a random time out, otherwise my object is undefined...
module.exports = {
getTable: async (req, res) => {
const tablename = req.params.table,
dbName = req.params.dbName;
let jsonResult = {};
getTableValues(dbName, tablename)
.then(tableValues => {
getTableIndexedCol(dbName, tablename)
.then(indexedColumns => {
let indexedArr = {};
for (let index = 0; index < indexedColumns.length; index++) {
const element = indexedColumns[index],
column = element.column_name,
referencedTable = element.referenced_table_name;
let allValuesRefTable = new Array();
getTableValues(dbName, referencedTable)
.then(referencedTableValues => {
for (let i = 0; i < referencedTableValues.length; i++) {
const el = referencedTableValues[i];
allValuesRefTable.push(el.name);
}
})
.catch(err => console.log(err));
/*IF NO TIMEOUT DOESN'T WORK*/
setTimeout(function(){
indexedArr[column] = allValuesRefTable;
}, 100);
}
setTimeout(function(){
jsonResult = {
name: tablename,
rows : tableValues,
rowIndexed : indexedArr
}
res.json(jsonResult);
}, 5000);
})
.catch(err => console.log(err));
})
.catch(err => console.log(err));
}
};
Is there a way to don't use setTimeout? or how can I 'wait' that the promise is resolved?
Here is my function getTableIndexedCol for example:
async function getTableIndexedCol(dbName, tablename) {
const sqlRefTable = SELECT...;
return new Promise (async function(resolve, reject){
try{
[refTable, refTableFields] = await promisePool.query(sqlRefTable)
}
catch(err){
reject(err)
}
setTimeout(function () {
resolve(refTable);
}, 500);
})
If you are already using async/await you can use it all the way and avoid the "Promise Hell" (nested .then calls):
module.exports = {
getTable: async (req, res) => {
try {
const tablename = req.params.table,
dbName = req.params.dbName;
const tableValues = await getTableValues(dbName, tablename);
const indexedColumns = await getTableIndexedCol(dbName, tablename);
let indexedArr = {};
for (let index = 0; index < indexedColumns.length; index++) {
const element = indexedColumns[index],
column = element.column_name,
referencedTable = element.referenced_table_name;
let allValuesRefTable = new Array();
const referencedTableValues = await getTableValues(dbName, referencedTable);
for (let i = 0; i < referencedTableValues.length; i++) {
const el = referencedTableValues[i];
allValuesRefTable.push(el.name);
}
indexedArr[column] = allValuesRefTable;
}
const = jsonResult = {
name: tablename,
rows: tableValues,
rowIndexed: indexedArr
}
res.json(jsonResult);
} catch (err) {
console.log(err);
}
}
};

Resources