Angular 将嵌套的HTTP请求合并到单个可观察对象中

Angular 将嵌套的HTTP请求合并到单个可观察对象中,angular,rxjs,observable,Angular,Rxjs,Observable,我有一个工作区模型,一个请求模型。。。现在是一个CatalogItem模型,需要将这两种模型结合起来,如下所示: { workspace: Workspace requests: Request[] } 我对如何使用getCatalog():Observable函数创建此函数有点困难。。。对于每个工作区,它应返回一个目录项,并向其中添加任何相关的请求 我意识到我的尝试还远远不够,但我希望这足以帮助理解我的意图: getCatalog(): Observable<CatalogIt

我有一个工作区模型,一个请求模型。。。现在是一个CatalogItem模型,需要将这两种模型结合起来,如下所示:

{
  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
为type
todoItem[]
在本例中,我只是返回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}))
    )
  );
}