Angular 将嵌套的HTTP请求合并到单个可观察对象中
我有一个工作区模型,一个请求模型。。。现在是一个CatalogItem模型,需要将这两种模型结合起来,如下所示:Angular 将嵌套的HTTP请求合并到单个可观察对象中,angular,rxjs,observable,Angular,Rxjs,Observable,我有一个工作区模型,一个请求模型。。。现在是一个CatalogItem模型,需要将这两种模型结合起来,如下所示: { workspace: Workspace requests: Request[] } 我对如何使用getCatalog():Observable函数创建此函数有点困难。。。对于每个工作区,它应返回一个目录项,并向其中添加任何相关的请求 我意识到我的尝试还远远不够,但我希望这足以帮助理解我的意图: getCatalog(): Observable<CatalogIt
{
workspace: Workspace
requests: Request[]
}
我对如何使用getCatalog():Observable
函数创建此函数有点困难。。。对于每个工作区
,它应返回一个目录项
,并向其中添加任何相关的请求
我意识到我的尝试还远远不够,但我希望这足以帮助理解我的意图:
getCatalog(): Observable<CatalogItem[]> {
return this.http.get<Workspace[]>(`${this.baseUrl}/workspace`).pipe(
switchMap( (ws) => {
return {
workspace: ws,
requests: this.http.get<Request[]>(`${this.baseUrl}/${ws.id}/requests`).subscribe();
}
})
);
//TODO: combine workspace and request create catalog obj
}
getCatalog():可观察{
返回此.http.get(`${this.baseUrl}/workspace`)管道(
开关映射((ws)=>{
返回{
工作空间:ws,
请求:this.http.get(`${this.baseUrl}/${ws.id}/requests`).subscribe();
}
})
);
//TODO:合并工作区和请求创建目录obj
}
查看您的代码,您似乎需要调用http。获取每个工作区的
以下是如何实现它,只需按照以下3个步骤操作即可。
1.
首先使用mergeAll
将Obsevable
(由get
返回)转换为流(这样我们可以一次处理一个工作区
)
2.
接下来使用mergeMap
调用http.get
并在使用map
的响应到达后形成一个新的CtalogItem
(利用闭包引用工作区
),将每个可观察的转换为可观察的
3.
最后,使用toArray
将流转换回数组
getCatalog():可观察{
返回这个.http.get(`URL/workspace`).pipe(
// 1
mergeAll(),
// 2
mergeMap(workspace=>this.http.get(`URL/${workspace.id}`).pipe(
映射(请求=>({workspace,requests})))
),
// 3
toArray()
)
}
mergeAll
可以将包含数组的可观察对象展平到流中,有关详细说明,请参阅RxJS可观察对象中“展平”数组的最佳方法
toArray
收集所有源排放,并在源完成时作为阵列排放。
这样做的目的是链接您的请求,使它们相互依赖,并使结果成为一个类似于您所布置的某种类型的合并对象
关键(至少从我在这方面的经验来看)是管道末端的toArray
getTodos(): Observable<SomeMergedObject[]> {
return this.http.get<TodoItem[]>('https://jsonplaceholder.typicode.com/todos').pipe(
mergeMap( resp => resp),
concatMap( (t: TodoItem) => {
console.log(t.userId)
return this.http.get<User>(`https://jsonplaceholder.typicode.com/users/${t.userId}`).pipe(
map( user => ({ todoItem: t, user } as SomeMergedObject))
)
}),
toArray()
);
}
您可以使用内部管道来解决问题:
getCatalog(): Observable<CatalogItem[]> {
return this.http.get<Workspace[]>(`${this.baseUrl}/workspace`).pipe(
switchMap(workspace => this.http.get<Request[]>(`${this.baseUrl}/${ws.id}/requests`).pipe(
map(requests => ({workspace, request}))
)
);
}
getCatalog():可观察{
返回此.http.get(`${this.baseUrl}/workspace`)管道(
switchMap(workspace=>this.http.get(`${this.baseUrl}/${ws.id}/requests`).pipe(
映射(请求=>({workspace,request}))
)
);
}
详情:
- 如果在switchMap中打开另一个
管道
,则仍然具有switchMap的上下文。这意味着您可以使用工作区
- 如果您的变量名是您想要作为属性的键(例如,
const key='test'
),您可以短写{key}
。这将创建一个对象{key:'test}
- 如果要返回映射内的对象,可以缩短
({…})
而不是{return{}
为了澄清,第二个调用取决于第一个调用的结果?(您不能让它们并行运行)对,我正在尝试进行嵌套调用(在获得工作区数据后,请求调用可以并行运行)…但希望将这一切都放在getCatalog()中…所以/{workspace\u id}/请求将添加与从/workspace callI返回的每个工作区相关联的请求。我在下面建议了一个工作答案。请告诉我这是否接近您想要的。查看mergedObject的界面…不应todoItem
为typetodoItem[]
在本例中,我只是返回todo,获取用户(通过todo.UserId)并合并两个user/todo对象。因此,结果实际上是SomeMergedObject[]
但您可以完全将其更改为TodoItem[]的返回类型
。我刚使用了一个合并对象,因为这看起来像是你在做的事情。如果你看一下stackblitz,其中有一个完整的工作示例。可能需要一秒钟来获取数据,因为它正在执行大量HTTP请求。我的意思是,SomeMergedObject.todoItem应该是一个数组(todoItems)作为“请求”在我的问题中。每个“SomeMergedObject”可能有0个或多个“todoItem”,您当然可以这样更改它。您可以按自己喜欢的方式形成一个对象。您是说,您实际上不是在尝试将两个不同的响应相互映射,而是尝试将它们合并到一个对象{allResponsesForResponse1:[,…],allResponsesForResponse2:[,…]}
getCatalog(): Observable<CatalogItem[]> {
return this.http.get<Workspace[]>(`${this.baseUrl}/workspace`).pipe(
switchMap(workspace => this.http.get<Request[]>(`${this.baseUrl}/${ws.id}/requests`).pipe(
map(requests => ({workspace, request}))
)
);
}