Smoothing Nested Observations

I was stuck in an enclosed observable hell and could do with a hand.

I have the following code code

return this.findUser(term).map( users => { return users.map( user => this.getLastLogin(user.user_id).map( last_login => { user.last_login = last_login; return user; })); }); 

findUser returns an Observable<User[]> and getLastLogin returns an Observable<number> .

I basically hope to get a list of users and then update it with information from a different value.

Currently, the above code returns <Observable<Observable<User>[]> .

I thought replacing the initial map with flatMap , but this will turn the object into <Observable<Observable<User>> .

The RxJS documentation is a bit hard to decrypt, so I'm not sure which combination of switch , forkJoin or flatMap will bring me what I need.

I hope to return Observable<User[]> . Can someone point me in the right direction?

+5
source share
2 answers

Actually for this you do not need forkJoin() and switch() .

In general, you want to update each user in the user array with another asynchronous call.

I would do it like this:

 var source = findUser('term') .mergeAll() .mergeMap(user => getLastLogin(user.user_id) .map(last_login => { user.last_login = last_login; return user; }) ) .toArray(); source.subscribe(val => console.log(val)); 

The mergeAll() operator converts an observable higher order into single observables. In this case, it takes an array of all users and re-selects them one by one. Then mergeMap() emits users updated with the last_login date. In the end, I used toArray() to convert single users into one large array that emits them as a whole (you can remove this operator if you want to emit single users).

Note that when you used return users.map(...) , you used Array.map() , which returns an array, not map() from RxJS, which returns Observable. I think that working with single objects is usually simpler than with arrays of objects.

See demo version: https://jsbin.com/naqudun/edit?js,console

Sent to the console:

 [ { name: 'foo', user_id: 42, last_login: 2016-11-06T10:28:29.314Z }, { name: 'bar', user_id: 21, last_login: 2016-11-06T10:28:29.316Z } ] 
+4
source

One solution would be to use forkJoin to combine and then display the results of the getLastLogin calls getLastLogin users:

 // forkJoin will return Observable<User[]>, so use switchMap. return this.findUser(term).switchMap(users => Observable.forkJoin( // Map the array of users to the array of observables to be joined. Use // first to ensure the observables complete. users.map(user => this.getLastLogin(user.user_id).first()), // Use forkJoin selector to add the last_login to each user and return // the users. (...logins) => { users.forEach((user, index) => { user.last_login = logins[index]; }); return users; } )); 
+1
source

Source: https://habr.com/ru/post/1259351/


All Articles