Paul
Paul

Reputation: 2620

RxJS: SwitchMap for Array of Strings

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

Answers (4)

Adam Dunkerley
Adam Dunkerley

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

Paul
Paul

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

wannadream
wannadream

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

martin
martin

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

Related Questions