Reputation: 2620
Following use case: A user can join 0...* groups. Each group has an ID and contains 0...* posts.
I subscribe to an Observable (to get the groups of the user he joined) and this returns an array of strings (the group IDs).
const groupIds$ = of(['a', 'b', 'c']);
If I only had one I would now use switchMap
and return this new observable and subscribe to it to get the posts from the group.
But so I have an array and so this isn't working. Does anyone has an idea which RxJS operator(s) can achieve this to get the posts from all groups?
Or does no operator for such use case exist and I have to do it separately at subscribe?
Upvotes: 4
Views: 12794
Reputation: 702
Terser improvement on great existing answers. This emits an array of all posts each time the groupIds$
source emits.
groupIds$.pipe(
switchMap(ids => zip(...ids.map(id => service.getPosts(id)))),
map((posts: Array<Post[]>) => [].concat.apply([], posts))
).subscribe(posts => /*is an array of all posts*/);
Upvotes: 0
Reputation: 2620
Everyone who arrives at this question, here is the answer for "switchMap for Array of strings" (thanks to martin). You only have to use 'merge' from 'rxjs' (not the operator!). Inside switchMap return merge and you are done:
groupIds$.pipe(
switchMap(groups => {
const observables = groups.map(id => {
// your function that returns the observable
return something.getObservable(id);
});
return merge(...observables);
})
).subscribe(data => {
console.log('DATA', data);
});
Upvotes: 5
Reputation: 1760
Possible solution: https://www.learnrxjs.io/operators/transformation/mergemap.html.
const groupIds$ = of(['a', 'b', 'c']);
const myPromise = id =>
new Promise(resolve => resolve(something.getPostsByGroupId(id)));
const posts$ = groupIds$.pipe(
mergeMap(
id => myPromise(id),
(valueFromSource, valueFromPromise) => {
return valueFromPromise;
}));
posts$.subscribe(...);
Upvotes: 0
Reputation: 96889
You can use ideally forkJoin
if you know you'll have all source Observables as an array:
groupIds$.pipe(
concatMap(groups => {
const observables = groups.map(id => ...);
return forkJoin(...observables);
})
).subscribe(...);
forkJoin
will emit a single array with all the results in the same order as in groupIds$
.
Eventually if you don't care about the order and just want to get all the results in parallel you can use merge
instead of forkJoin
(I mean the "Observable creation method" called merge
imported directly from rxjs
. Not the merge
operator from 'rxjs/operators'
).
Upvotes: 6