Loop array and return data for each id in Observable
This is quite possible using nested mergeMap
and map
. A key approach to stick with Observable is expanding the contacts array into an observable using from
function. Then you collect the data using toArray
operator. Providing documented example:
public getCombinedData(): Observable<any> {
return this.getMultipleRelationData()
.pipe(
mergeMap((result: any) =>
// `from` emits each contact separately
from(result.contact).pipe(
// load each contact
mergeMap(
contact => this.getSignleData(contact._id),
// in result selector, connect fetched detail
(original, detail) => ({...original, relationship: detail})
),
// collect all contacts into an array
toArray(),
// add the newly fetched data to original result
map(contact => ({ ...result, contact})),
)
),
);
}
Edit: result selector is deprecated
In the inner mergeMap
, you can use a map
afterwards.
public getCombinedData(): Observable<any> {
return this.getMultipleRelationData().pipe(
mergeMap((result: any) =>
// `from` emits each contact separately
from(result.contact).pipe(
// load each contact
mergeMap(
contact =>
this.getSignleData(contact._id).pipe(
map(detail => ({ ...contact, relationship: detail })),
),
// collect all contacts into an array
toArray(),
// add the newly fetched data to original result
map(contact => ({ ...result, contact })),
),
),
),
);
}
Although kvetis's answer can work for you here is what I implemented, just posting it because I found it interesting to solve.
public getCombinedData(): Observable<any> {
return this.getMultipleRelationData()
.pipe(
mergeMap((result: any) => {
let allIds = result.contact.map(id => this.getSingleData(id._id));
return forkJoin(...allIds).pipe(
map((idDataArray) => {
result.contact.forEach((eachContact, index) => {
eachContact.relationship = idDataArray[index];
})
return result;
})
)
})
);
}
Here is an example solution for your question, I have made dummy Observables. https://stackblitz.com/edit/angular-tonn5q?file=src%2Fapp%2Fapi-calls.service.ts