I have 3 dependent Rest API resources (lets say observables) like this:
1st observable produces one item as array of users, like this:
getUsers(): Observable<User[]>
[
{
"id": 1,
"name": "Peter",
"surname": "Smith"
},
{
"id": 2,
"name": "John",
"surname": "Wayne"
},
...
]
2nd observable can be used to fetch addresses assigned to user, so the input parameter is User ID, and returns a one item as array of addresses:
getUserAddresses(user_id: string): Observable<Address[]>
[
{
"id": 1,
"city": "London",
"street": "Wicombe 34"
},
{
"id": 2,
"city": "Paris",
"street": "La fever 20"
},
...
]
3rd observable can be used to fetch companies assigned to user, so the input parameter is User ID, and returns a one item as array of companies:
getUserCompanies(user_id: string): Observable<Company[]>
[
{
"id": 1,
"name": "Fintch CO",
"state": "France"
},
{
"id": 2,
"name": "C&C inc.",
"state": "USA"
},
...
]
I want to chain these 3 observables into one which will produce the result again as one item, that will contain array of users with their additional addresses arrays and companies array, like following:
[
{
"id": 1,
"name": "Peter",
"surname": "Smith",
"addreesses":
[
{
"id": "1",
"city": "London",
"street": "Wicombe 34"
},
{
"id": "2",
"city": "",
"street": "La fever 20"
}
],
"companies":
[
{
"id": "1",
"name": "Fintch CO",
"state": "France"
},
{
"id": "2",
"name": "C&C inc.",
"state": "USA"
}
]
}
},
{
"id": 2,
"name": "John",
"surname": "Wayne",
"addresses": [...],
"companies": [...],
},
...
]
How should look like the operators composite to achieve that in Angular 6 with RxJs 6? Thanks a lot for advice.
Something like this could work
getUsers()
.pipe(
switchMap(users => from(users)),
mergeMap(user => forkJoin(getAddresses(user.id), getCompanies(user.id))
.pipe(map(data => ({user, addresses: data[0], companies: data[1] })))
tap(data => data.user.addresses = data.addresses),
tap(data => data.user.addresses = data.companies),
map(data => data.user),
toArray()
)
)
Applied to a different use case a similar chain is explained in more details here.
To chain observables, you can use the flatMap
function. This function is like promises then, meaning the function is only executed once the observable has resolved to a value.
There is also an observable function called forkJoin
which allows you to wait for multiple async requests to all have resolved to a value.
Example:
getUsers().flatMap((users) => {
// the users variable is the list of users
var multipleObservables = [];
users.forEach((u) => {
multipleObservables.push(
getUserAddresses(u.id).map((usersAddresses) => {
u.addresses = usersAddresses;
return u;
});
);
});
return forkJoin(multipleObservables);
}).flatMap((usersWithAddresses) => {
// the usersWithAddresses variable is an array of users which also have their addresses
var multipleObservables = [];
usersWithAddresses.forEach((u) => {
multipleObservables.push(
getUserCompanies(u.id).map((usersCompanies) => {
u.companies = usersCompanies;
return u;
});
);
});
return forkJoin(multipleObservables);
});
You can write something like this to chain you request and grow your user objects.
Here are the operators for combination, these emit the result in an array (reference):
- combineAll
- combineLatest
- forkJoin
- pairwise
- zip (the solution I would suggest)
I would suggest giving them all a read, to work out what you would prefer and find best for your scenario.
Hope this helps!
来源:https://stackoverflow.com/questions/51210629/angular-6-pipe-rxjs-operator-to-chain-3-dependant-observables