Reputation: 63
I have a /get route that get some data from database and send it to the user. The problem is that I use two functions with a async.forEachOf statement in them. I don't know how to wait until the second async.forEachof is complete then to send the whole result back to the user.
I think that I need to use a Promise or something like that but I can't manage how to use this in my functions. Can someone please help me this bothers me for two days already. Thank you and have a great day.
These are the functions :
function getSetsFromWorkout(workouts) {
const selectSetsQuery = "SELECT id, set_number, workoutFKEY FROM sets WHERE workoutFKEY = ?"
async.forEachOf(workouts, function (workout, key, callback) {
const workoutId = workout.id
getConnection().query(selectSetsQuery, [workoutId], (err, setsRows, result) => {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
workout["sets"] = setsRows
getExercisesFromSets(workout)
}
callback()
});
}, function (err) {
if (err) console.log(err.message);
});
};
function getExercisesFromSets(sets) {
const selectExercisesQuery = "SELECT id, ex_time, type, ex_id FROM user_exercises WHERE setsFKEY = ?"
const allSets = sets["sets"]
async.forEachOf(allSets, function (set, key, callback) {
const setId = set.id
getConnection().query(selectExercisesQuery,[setId], (err, exercisesRows, result)=> {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
console.log("add exercise")
set["exercises"] = exercisesRows
callback()
}
});
}, function(err) {
if (err) console.log(err.message)
console.log("ENDED")
console.log(sets)
});
};
This is the output based on console.log() statement. The result is what i need but i don't know how to send it only after the forEachOf loop is finished.
If I put res.json(sets) here it will send back to the client only the first iteration of forEachOf then it will stop.
function(err) {
if (err) console.log(err.message)
console.log("ENDED")
console.log(sets)
**res.json(sets)**
});
};
I need to wait for all the iterations to be complete, then to send the data to sclient.
add exercise
add exercise
add exercise
ENDED
//MY data from db
add exercise
ENDED
// My other set of data from db
Upvotes: 0
Views: 2360
Reputation: 11
You can always use a promise for the inner async.forEachOf
(the one in getExercisesFromSets()
), by wrapping the second async code in a returned promise. And the promise will only get fulfilled when the async has finished, i.e., after the error check. Then call the first function's callback only after the second function is called and it has fulfilled the promise (i.e. in promise.then()
). This will ensure a set is only counted after all the exercises in it are counted. Like this:
function getSetsFromWorkout(workouts) {
const selectSetsQuery = "SELECT id, set_number, workoutFKEY FROM sets WHERE workoutFKEY = ?"
async.forEachOf(workouts, function (workout, key, callback) {
const workoutId = workout.id
getConnection().query(selectSetsQuery, [workoutId], (err, setsRows, result) => {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
workout["sets"] = setsRows
getExercisesFromSets(workout).then(() => callback())
}
});
}, function (err) {
if (err) console.log(err.message);
//do whatever you want with the final workouts array here
});
};
function getExercisesFromSets(sets) {
return new Promise((fulfill, reject) => {
const selectExercisesQuery = "SELECT id, ex_time, type, ex_id FROM user_exercises WHERE setsFKEY = ?"
const allSets = sets["sets"]
async.forEachOf(allSets, function (set, key, callback) {
const setId = set.id
getConnection().query(selectExercisesQuery,[setId], (err, exercisesRows, result)=> {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
console.log("add exercise")
set["exercises"] = exercisesRows
callback()
}
});
}, function(err) {
if (err) console.log(err.message)
console.log("ENDED")
console.log(sets)
fulfill()
});
});
};
Upvotes: 1
Reputation: 976
I think you could create a function that will be called by the async.forEach
callbacks and a variable to check if both processes have ended (for example, could be some different approaches to get the same result). Something like this:
var ended = { array1: false, array2: false };
const dataToReturn = {};
const array1 = [];
async.forEachOf(array1, function (item, key, callback) {
// do stuff
dataToReturn.array1 = "first data";
callback();
}, function (err) {
if (err) console.log(err.message);
else {
ended.array1 = true;
endProcess();
}
});
const array2 = [];
async.forEachOf(array2, function (item, key, callback) {
// do stuff
dataToReturn.array2 = "first data";
callback();
}, function (err) {
if (err) console.log(err.message);
else {
ended.array2 = true;
endProcess();
}
});
function endProcess() {
if (!ended.array1 || !ended.array2) return;
res.json(dataToReturn);
}
Upvotes: 1
Reputation: 237
If I understand correctly, you need to send the exercise sets returned from selectExercisesQuery for all workouts sets. Following changes below highlighted with comment should work:
function getSetsFromWorkout(workouts) {
const selectSetsQuery = "SELECT id, set_number, workoutFKEY FROM sets WHERE workoutFKEY = ?"
async.forEachOf(workouts, function (workout, key, callback) {
const workoutId = workout.id
getConnection().query(selectSetsQuery, [workoutId], (err, setsRows, result) => {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
workout["sets"] = setsRows
getExercisesFromSets(workout)
}
callback()
});
}, function (err) {
if (err) console.log(err.message);
res.send(workouts); // -------------------Workout object has all the info you need as it is being passed and updated by reference.
});
};
function getExercisesFromSets(sets) {
const selectExercisesQuery = "SELECT id, ex_time, type, ex_id FROM user_exercises WHERE setsFKEY = ?"
const allSets = sets["sets"]
async.forEachOf(allSets, function (set, key, callback) {
const setId = set.id
getConnection().query(selectExercisesQuery,[setId], (err, exercisesRows, result)=> {
if (err) {
console.log("Failed to query for users: "+ err)
res.sendStatus(500)
res.end()
} else {
console.log("add exercise")
set["exercises"] = exercisesRows
callback()
}
});
}, function(err) {
if (err) console.log(err.message)
console.log("ENDED")
sets["sets"] = allSets //--------------assign the updated allSets array back to referenced sets.
console.log(sets)
});
};
Upvotes: 0