I have an array of objects like this:
results from an aggregate give me a result with same structure as follows:
results = [
{id: 1, test: biology, candidates:[ {cid: 11},{cid: 12},{cid: 13}]},
{id: 2, test: chemistry, candidates:[ {cid: 15},{cid: 16},{cid: 17}]},
{id: 3, test: physics, candidates:[ {cid: 1},{cid: 6},{cid: 7}]}
];
So i need to loop in the array, then for each candidate call a promise function getTotalMarksPerCandidate(that has a Promise.all and resolve the variable after some computations). However, since looping in array, does not wait for promise to complete, I get promise...
Question: do you know how can i work this out so that when looping in my candidates array, it waits for results and continue? or any turnaround solutions?
So I map into the results array, then did a forEach in the candidates array, call the function getTotalMarksPerCandidate with the candidate object as parameter, push the result in a promise array. Then will resolve all promises received.
var new_Result = results.map( function (subject) {
let promises = [];
if (subject.candidates && subject.candidates.length > 0) {
subject.candidates.forEach( (element) => {
promises.push(mobileUtil. getTotalMarksPerCandidate(element));
});
}
return Promise.all(promises).then( result => {
console.log('Check this out', result);
subject.newCandidatelist = result;
return subject;
});
});
console.log('R: ', new_Result);
resolve(params);
So in the return Promise.all(promises) callback function, I can see at that the promises are being resolved and i see the returning value from the function getTotalMarksPerCandidate. How can i do to set the new candidates object with the totalMarks to their respective parent object like
new_results = [
{id: 1, test: biology, candidates:[ {cid: 11, score: 88},{cid: 12, score: 90},
{cid: 13, score: 91}]},
{id: 2, test: chemistry, candidates:[ {cid: 15, score: 91},{cid: 16, score: 91},
{cid: 17, score: 91}]},
{id: 3, test: physics, candidates:[ {cid: 1, score: 91},{cid: 6, score: 91},
{cid: 7, score: 91}]}
];
Thank you
One approach to this that is based solely on a nested Promise
chain would be as follows:
/*
Obtain array of promises via results.map() and resolve each sequentially
*/
const new_Result = Promise.all(results.map((subject) => {
/*
Start a promise chain for this subject
*/
return Promise.resolve()
.then(() => {
/*
Get candidates from current subject, or just an empty array if no valid candidates data present
*/
const candidates = Array.isArray(subject.candidates) && subject.candidates.length > 0 ? subject.candidates : [];
/*
Map candidates (if any) to this Promise.all()
*/
return Promise.all(candidates.map((candidate) => {
return mobileUtil.getTotalMarksPerCandidate(element).then(function(score) {
/*
Assign the score returned from getTotalMarksPerCandidate() for current candidate object
*/
candidate.score = score;
/*
Return the updated candidate to mapped array of promise results
*/
return candidate;
})
}));
})
.then((result) => {
console.log('Check this out', result);
subject.newCandidatelist = result;
return subject;
});
}));
The key addtion here are these lines, which basically "attaches" the score value returned from the resolved promise of getTotalMarksPerCandidate()
to the current candidate
being iterated:
return mobileUtil.getTotalMarksPerCandidate(element).then(function(score) {
candidate.score = score;
return candidate;
})
Hope that helps!
With async/await the flow can be
(async () => {
try {
const new_Result = results.map(({ candidates, ...rest }) => {
const updatedCandidates = candidates.map(async candidate => {
const score = await getTotalMarksPerCandidate(candidate)
return { score, ...candidate }
})
return { candidates: updatedCandidates, ...rest }
})
console.log(new_Result)
} catch(err) {
// handle error
}
})()
Thank you Dacre & Chridam & Bergi for taking the time to respond to this issue. So i tried both solutions and tweaked Dacre solution a bit and it worked and i got what i needed on my front end.
Params is a json object i passed as parameter to my function. mobileUtil.getTotalMarksPerCandidate is a function being called, that return an object with the amended Marks in the object itself sent through as parameter initially.
Promise.all( results.map( jobtitle => {
return Promise.resolve()
.then(() => {
const candidates = Array.isArray(subject.candidates) && subject.candidates.length > 0 ? subject.candidates : [];
/*
Map candidates (if any) to this Promise.all()
*/
if (candidates && candidates.length > 0)
{
return Promise.all(candidates.map((candidate) => {
return mobileUtil. getTotalMarksPerCandidate(candidate).then( function(candidate) {
/*
Return the updated candidate to mapped array of promise results
*/
return candidate;
})
}));
}
})
.then((result) => {
return subject;
});
})
).then( res => {
params.listofnewCandidates = res;
resolve(params);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.