我试图使多个http请求依赖于上一个请求,并将返回的数据组合到最终结果对象中。
我有两个端点:
/properties
会给我类似的信息:
{
"data":[
{
"id":1,
"name":"Property 1",
"units":[
{
"id":1,
"name":"Property 1 - Unit 1",
},
{
"id":2,
"name":"Property 1 - Unit 2",
},
],
},
{
"id":2,
"name":"Property 2",
"units":[
{
"id":3,
"name":"Property 2 - Unit 3",
}
]
}
]
}```
/properties/${property.id}/units/${unit.id}/bookings
会向我返回一些与先前请求相关的对象,例如:
{
"data": {
"id": 1
},
"meta": {
"count": 5
}
}
我想要实现的是将这两个响应在单个单元级别上组合为一个。 像这样:
{
[
...
{
"id":2,
"name":"Property 2",
"units":[
{
"id":3,
"name":"Property 2 - Unit 3",
"bookings_meta": {
"count":5
}
}
]
}
]
}
我创建了类似的东西,并且效果很好:
list(): Observable<any> {
return this.http.get('/properties').pipe(
map((results: any) => results.data),
flatMap((properties: any[]) => {
if (properties.length > 0) {
return forkJoin(properties.map((property: any) => {
return forkJoin(property.units.map((unit: any) => {
return this.http.get(`/properties/${property.id}/units/${unit.id}/bookings`).pipe(
map(({ meta }) => {
unit.bookings_meta = meta
return unit;
})
)
}))
}))
}
return of([]);
})
);
}
this.list().subscribe(response => {
console.log(response)
})
但是我认为这不是100%正确的解决方案。
我感觉forkJoin
太多了,也许不应该flatMap
那里呢?
单元之间的预订请求应独立。
有人对如何改进上面的代码有想法吗?
答案 0 :(得分:1)
forkJoin
将在所有调用结束后返回数据并返回结果
const combined = Observable.forkJoin(
this.http.get('https:// ...properties').map((res: Response) => res.json()),
this.http.get('https:// ..properties/${property.id}/units/${unit.id}/bookings')
.map((res: Response) => res.json())
)
combined.subscribe(latestValues => {
console.log( "latestValues" , latestValues );
});
更新:
可以使用flatMap
运算符将一个Observable发出的项目转换为另一个Observable。它创建一个内部Observable
并将其结果平坦到外部流。
list(): Observable<any> {
return this.http.get('/properties')
.flatMap(properties => properties.map(p => p.units.map(unit =>
{
this.http.get(`/properties/${property.id}/units/${unit.id}/bookings`)
})))
.subscribe(res => { // some actions });
}
答案 1 :(得分:0)
最后我找到了一个可观察到的地狱的答案:)
list(): Observable<any> {
return this.http.get('/properties').pipe(
map((results: any) => results.data),
mergeMap((properties: any[]) => forkJoin(
properties.map((property: any) => forkJoin(
property.units.map((unit: any) => this.http.get(`/properties/${property.id}/units/${unit.id}/bookings`).pipe(
map(({ meta }) => ({ ...unit, meta }))
))
)).pipe(map((units: any[]) => ({ ...property, units }))))
))
);
}
干杯!