I have prepared this example on Stackblitz for my question. In this Angular app, I have a NestedSolutionComponent
with my current working solution and an AppComponent
, where I want to achieve the same result by using proper rxjs operations.
For a real world example which is a bit more complex, I am looking for a solution to map the results of my multiple inner subscription to an array of my outer subscription.
A REST call for a user service provides me this array:
[
{
id: 1,
name: 'User One',
groupIds: [1, 3]
},
{
id: 2,
name: 'User Two',
groupIds: [2, 3, 4]
},
]
And for each group, I would like to call a REST group service that is providing me further infos about the user group. All in all, I call the group service 5 times, each ID in the group array gets called once. When finished, the result should be mapped into the groups array - but instead of solely having the ID, the whole object should be stored into the array.
The solution should look like this:
[
{
id: 1
name: 'User One'
groups: [
{ id: 1, name: 'Group One' },
{ id: 3, name: 'Group Three' }
]
},
{
id: 2
name: 'User Two'
groups: [
{ id: 2, name: 'Group Two' },
{ id: 3, name: 'Group Three' },
{ id: 4, name: 'Group Four' }
]
}
]
By nesting subscription, the solution is easy - but ugly. I call the user service first, then calling for each user each groups:
this.appService.getUsers().subscribe((users) => {
const _usersWithGroupNames = users.map((user) => {
const userWithGroupNames = {
id: user.id,
name: user.name,
groups: [],
} as UserWithGroupNames;
user.groupIds.forEach((groupId) => {
this.appService.getGroupById(groupId).subscribe((groupWithName) => {
userWithGroupNames.groups.push({
id: groupWithName.id,
name: groupWithName.name,
});
});
});
return userWithGroupNames;
});
this.usersWithGroupNames.next(_usersWithGroupNames); // Subject
});
I have spent hours and hours but I really do not see any solution with proper rxjs operators. I tried switchMap
and mergeMap
but ended in a hell of nested map operations. Also forkJoin
seems not to help me out here, since I receive an array and I have to call the inner subscriptions in a certain order. When I call multiple mergeMaps in a pipe, I cannot access the previous values. I would like to have a solution like that
// not real code, just dummy code
userService.pipe(
xmap(users => generateUsersWithEmptyGroupArray()),
ymap(users => users.groups.forEach(group => groupService.getGroup(group)),
zmap((user, groups) => mapUserWithGroups(user, groups)) // get single user with all group information
).subscribe(usersWithGroups => this.subject.next(usersWithGroups))
Anybody here who knows a proper and readable solution for my problem?
Thanks a lot in advance!