I'm using an observable to query my DB. This observable will return an array with all the matching objects found. My problem is that I want to map the observable with more details that I will retrieve from another API.
I tried concatMap but it only let me nest 1 observable inside the initial observable
const usersAPI$: Observable<Users[]> = // something
const assistsAPI$: Observable<Assists[]> = // something
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists =>
assists.map(assist => usersAPI$.get(assist.userID)
.pipe(
map(user =>
assist = {...assist}, ...{userName: user.userName}
)
)
)
)
);
You can see a similar working example here, on stackblitz, https://stackblitz.com/edit/rxjs-concatmap-issue-stackoverflow where the "result" is the correct way of using concatMap and the "result2" is the non working way that I expected to work
You have to process your inner array of Observables in some way. You could use forkJoin
, merge
or concat
depending on your needs.
forkJoin
will process your inner API calls in parallel and return an array when all API calls complete. Note that the inner Observables have to complete. I think this is what should suit you in your app.
import { forkJoin } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => forkJoin(assists.map(assist => someObservable ))
);
merge
will subscribe to all inner API calls at once and emit the results of all calls one by one as they arrive.
import { merge } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => merge(...assists.map(assist => someObservable )),
// toArray() add the toArray operator if you need the result as an array
);
This will give you the desired result in your stackblitz, but I think your stackblitz is somewhat missleading and not what you're looking for in the example code from your question, as the inner Observable in your stackblitz emits multiple times and the final output isn't an array. If the order of the inner requests doesn't matter, they all emit one value and then complete and you need the results of all request as an array just use forkJoin
.
concat
will subscribe to all inner API calls one after another. The next Observable in the sequence will only be subscribed to after the previous completed. The execution will therefore be slower than with forkJoin
or merge
as the next HTTP request will only be executed after the previous returned a value. Use this if the calls to your userAPI
specifically have to be made in the same order as the assists
in your array.
import { concat } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => concat(...assists.map(assist => someObservable )),
// toArray() add the toArray operator if you need the result as an array
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With