I know this has been asking thousands of times, but I still haven't been able to find an answer. I have a forEach loop that I am using to loop through a list of users and retrieving specific location data for each. Inside the forEach the first function call gets the branch then the second gets information on that branch.
The problem is that the forEach loop is not completing prior to returning data from the function, which is causing all sorts of issues.
Here is my code:
//getAllUserData() - this is the function which returns prematurely
const getAllUserData = async () => {
const sequelize = DB.GetDB('mcaintranet');
const userDB = MCAIntranet.initModels(sequelize);
userDB.tblUsers.belongsTo(userDB.tblSMSSent, { foreignKey: 'collector', targetKey: 'user' });
userDB.tblSMSSent.hasMany(userDB.tblUsers);
let users = await userDB.tblUsers.findAll({
attributes: ['collector', 'id'],
include: {
model: userDB.tblSMSSent,
attributes: [[sequelize.fn('COUNT', 'tblSMSSent.id'), 'numMessages']]
},
raw: true,
group: ['collector', 'tblUsers.id'],
})
//return list of all users and texts sent
//UserName, User Province Code, # Messages Sent, user Number
try {
await users.forEach(async user => {
const branch = await Users.getUserBranch(user);
const province = getKey(branch);
user.province = province;
// console.log("User: ", [user, branch])
//clean up JSON from join results
user.numMessages = user["tblSMSSent.numMessages"];
delete user["tblSMSSent.numMessages"];
})
const obj = { 'users': users };
console.log("DONE: ", obj)
return obj;
}
catch (ex) {
console.log("ERROR: ", ex)
const msg = ex.Message;
return { results: "False", message: "SMS.js 61" + msg }; //is user allowed to use SMS page)
}
}
//getUserBranch() - accessor function to return branch number
const getUserBranch = async (user) => {
// console.log("Branch User: ", user)
let branch = getUserProps(user.collector ? user.collector : user, 'branch');
// console.log(props)
if (!branch) branch = 0;
return branch;
}
//getUserProps - pulls all user properties from database and filters as necessary
const getUserProps = async (user, propName = null) => {
let ret = {};
if (user.collector) user = user.collector;
user = user.trim();
let filter = {
collector: user
}
if (propName) {
filter.propertyName = propName
}
// console.log("Filter: ", filter)
const sequelize = DB.GetDB('MCAIntranet');
const propsDB = MCAIntranet.initModels(sequelize);
//get all values contained for user
let props = await propsDB.tblUserProperties.findAll({
attributes: ['id', 'propertyName', 'propertyValue', 'updated'],
where: filter,
order: [['updated', 'DESC']],
})
// console.log("Props: ", props);
let distinctProps = await propsDB.tblUserProperties.findAll({
attributes: ['propertyName'],
DISTINCT: true,
where: filter,
})
//the SMS Credits item is sometimes added as a second row
//so loop through all potential value rows for user
distinctProps.forEach(dr => {
// console.log(dr);
var name = dr.propertyName.toLowerCase();
// console.log("name: ", name)
try {
//get individual values for each property user possesses
let tmpRows = props.filter(row => row.propertyName.toLowerCase() == name);
// console.log("tmpRows: ", tmpRows)
//get the most recent value
let row = tmpRows[tmpRows.length - 1];
var item = row.propertyName.trim();
var value = row.propertyValue.trim();
//add to returned JSON
ret[item] = value;
} catch (ex) {
console.log("USERS.js 157 " + ex.message);
return ({ error: "USERS.js 158" + ex.Message });
}
})
// console.log("Ret: ", ret)
return ret;
}
//getKey() - returns necessary data about the user province
const getKey = (data) => {
let branch;
try {
branch = data.branch ? data.branch : data;
}
catch (ex) {
console.log(data)
console.log(ex)
}
branch = parseInt(branch);
// console.log(branch)
try {
let acctKey = "";
let province = "";
let abbr = "";
// console.log("Branch: ", branch)
switch (branch) {
case 4: //vancouver
case '4':
abbr = "BC";
acctKey = key["BC"];
province = "British Columbia";
break;
case 7: //Montreal
case '7':
abbr = "QC";
acctKey = key["QC"];
province = "Quebec";
break;
case 9: //Toronto
case '9':
abbr = "ON";
acctKey = key["ON"];
province = "Ontario";
break;
default: //Edmonton
abbr = "AB";
acctKey = key["AB"];
province = "Alberta";
break;
}
return { key: acctKey, province: province, abbr: abbr };
}
catch (ex) {
throw ex;
}
}
Somewhere in this conglomeration of awaits and asyncs something is lacking causing the getAllData() function to return user names without the location data. How can I block execution until I have all the data? Please ignore the extraneous awaits I have put in while endeavoring to solve this problem.
Thanks.