Home > Blockchain >  Why rxjs' mergeMap turns array into separate objects
Why rxjs' mergeMap turns array into separate objects

Time:10-12

I am not Typescript, Javascript or frontend developer at all. I have inherited Angular 13 project. There is a function returning Observable<Dto[]>. I see something along this lines in the code:

this.service.getStuff(arg).pipe(
    mergeMap(x => x),
    concatMap(y => { return this.service.getOtherStuff(x.subObj.id).pipe(
        map(v => ({ obj1: y, obj2: v})));
    })
).subscribe(
// ... do something with results

I understand what it does and why it does that, but I can't for the life of me understand why would mergeMap turn an array into a stream of separate values. Documentation says only that mergeMap:

Projects each source value to an Observable which is merged in the output Observable

My understanding is that source value in this case is Dto[], so projection should be Observable<Dto[]>, not a list of Observables created from separate values in the array.

I suspected that maybe this maneuver is done later, but putting tap with console.log around mergeMap shows that input is indeed an array and output is a stream objects.

So what is happening and why? And why isn't it explained in the documentation while we're at it.

CodePudding user response:

The issue here is that you are using mergeMap not how it is normally intended. The map operators like mergeMap or switchMap expect an Observable (or a Promise) as the return value. But you are just returning the plain array. It seems like mergeMap sees that this is not an Observable and wraps it in a from operator. This creates an Observable from the array where each element emits individually.

If you do not want this behavior, wrap your value in of.

mergeMap(x => of(x))

But really this mergeMap does not have any effect either way. Why are you using this do-nothing function here? If you don't plan to return an Observable, why not use a map?

CodePudding user response:

This is intended behavior. If you look at the documnetation it says that the project function needs to return ObservableInput and not just Observable. In fact, all RxJS operators that expect an Observable as a parameter will work with any ObservableInput.

ObservableInput can be for example an Observable (obviously), async generator, an array or a Promise.

So using mergeMap(x => x) is really only used to unwrap the array and is equivalent to mergeMap(x => from(x)). Maybe more clean solution would be using just mergeAll() operator that is intended to be used with higher-order Observables.

  • Related