Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
702 views
in Technique[技术] by (71.8m points)

javascript - Flattening nested Observables

I'm a stuck in nested observable hell and could do with a hand.

I have the following block of 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 Observable<User[]> and getLastLogin returns Observable<number>.

I'm basically hoping to fetch a list of users and then update this with the information from another value.

Right now the code above is returning <Observable<Observable<User>[]>.

I thought I could replace the initial map with flatMap but this turns the object into <Observable<Observable<User>>.

The RxJS documentation is a little hard to decipher so I'm not sure what combination of switch, forkJoin or flatMap will get me to what I need.

I'm hoping to return Observable<User[]>. Could anyone point me in the right direction?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Actually, you don't need forkJoin() nor switch() to do this.

In general, you want to update each user in the array of users by another async call.

I'd 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));

Operator mergeAll() converts a higher-order Observable into single observables. In this case it takes the array of all users and re-emits them one by one. Then mergeMap() emits users updated with the last_login date. At the end I used toArray() to transform single users into one large array that is them emitted as whole (you can remove this operator if you want to emit single users instead).

Note that when you used return users.map(...) you were using Array.map() that returns an array and not map() from RxJS that returns an Observable. I think working with single objects is usually easier that with arrays of objects.

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

This prints to 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 } ]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...