0

I want to query to different rest resources and want to combine the results into a single object. Its a user object and every user should contain a single role. I have read I can use flatMap to do this, but I cant make it work:

public getUsers(): Observable<User[]> { var users: Observable<User[]> = this.someService.getUsers('[A_URL]') // returns Observable<User[]> .flatMap(res=> { // for every user call resource 'role' and add it to user object one by one ... // return this.someService.getRoleByUser('[A_URL_WITH_USERID]') }.map(res=>{ //add role to user object // user.role = r; }); ); return users; } 

Im sorry for the pseudo code, but I really dont understand the syntax. The problem is, that the second resource call needs the id of every user from the first call.

1 Answer 1

2

Here's how you can do it :

// This obs emits a SINGLE array of all users. // Analog to what your `.getUsers()` method would return const usersArray = Rx.Observable.of([ { id: 1, name: 'user1' }, { id: 2, name: 'user2' }, { id: 3, name: 'user3' } ]); // Obtain the role(s) for a given user. const userRoles = function(userId) { return Rx.Observable.of(`Role for user ${userId}`); } const obs = usersArray // Flatten the array. // Now each user is emitted as an individual value. .mergeMap(val => val) // Fetch user roles .mergeMap(user => { return userRoles(user.id).map(role => { // Put together user + role user.role = role; // DO NOT FORGET to return below return user; }); }) // At this point, you have individual users with a `user.role` property // being emitted in the stream. // Unflatten the array if desired (to obtain a SINGLE array of ALL users) .reduce((acc, curr) => acc.concat(curr), []); // Final subscribe obs.subscribe(val => console.log(val)); 

JS BIN demoing this code: http://jsbin.com/vucuga/4/edit?js,console

Notes:

  • flatMap() is an alias for mergeMap(). In RxJS 5 (which Angular uses), I believe mergeMap() is the "official" operator.
  • If you need to preserve the order of your users, use concatMap() instead of mergeMap().
Sign up to request clarification or add additional context in comments.

5 Comments

I believe flatMap is not existing in RxJS 5 :) gist.github.com/btroncone/d6cf141d6f2c00dc6b35
Indeed. That's what I wrote in the "notes". :)
Thank you. Now it tells me that role is not a property of user. How can I preserve the type?
The role property should be present in the definition of the User type. You can make it optional with a ?: { role?: string; }
Now I changed the second merge to "mergeMap((user: User) => {" and its working! Thanks a lot!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.