【问题标题】:Combine nested HTTP requests in single observable将嵌套的 HTTP 请求合并到单个 observable 中
【发布时间】:2020-12-09 03:27:56
【问题描述】:

我有一个 Workspace 模型、一个 Request 模型......现在还有一个 CatalogItem 模型,它需要像这样将两者结合起来:

{
  workspace: Workspace
  requests: Request[]
}

我在如何使用getCatalog(): Observable<CatalogItem[]> 函数创建它时遇到了一些困难……它应该为每个Workspace 返回一个CatalogItem,并添加任何关联的Request

我意识到我的尝试很遥远,但我希望它足以帮助理解我的意图:

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() 中。 . 所以 /{workspace_id}/requests 将添加与从 /workspace 调用返回的每个工作空间相关联的请求
  • 我在下面提出了一个可行的答案。让我知道这是否接近您想要的。

标签: angular rxjs observable


【解决方案1】:

查看您的代码,您似乎需要为每个workspace 调用http.get&lt;Request[]&gt;

以下是如何实现它,只需按照以下 3 个步骤操作即可。

1.
首先使用mergeAllObsevable&lt;Workspace[]&gt;(由get&lt;Workspace[]&gt; 返回)转换为流(这样我们一次可以处理一个workspace)。

2.
接下来使用mergeMap 将每个Observable&lt;Workspace&gt; 转换为Observable&lt;CatalogItem&gt;,方法是调用http.get&lt;Request[]&gt; 并在使用map 的响应到达后形成一个新的CtalogItem(利用闭包引用workspace)。

3.
最后使用toArray将流转换回数组。


getCatalog(): Observable<CatalogItem[]> {
  return this.http.get<Workspace[]>(`URL/workspace`).pipe(

   // 1  
    mergeAll(),

   // 2  
    mergeMap(workspace => this.http.get<Request[]>(`URL/${workspace.id}`).pipe(
      map(requests => ({ workspace, requests })))
    ),

   // 3  
    toArray()

  )
}

mergeAll 可以将包含数组的 Observable 展平为流,有关进一步说明,请参阅 @Martin's post 关于在 RxJS Observable 中“展平”数组的最佳方法

toArray 收集所有源发射,并在源完成时将它们作为数组发射。

【讨论】:

    【解决方案2】:

    您可以使用内管来解决您的问题:

    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}))
        )
      );
    }
    
    

    详情:

    • 如果您在 switchMap 中打开另一个 pipe,您仍然拥有 switchMap 的上下文。这意味着您可以使用workspace
    • 如果您的变量名称是您想要的键(例如const key = 'test')作为属性,您可以简写为{ key }。这将创建一个对象{ key: 'test }
    • 如果你想在地图中返回一个对象,你可以写成({ ... })而不是{ return {} }

    【讨论】:

      【解决方案3】:

      Here's an example:

      这个想法是将您的请求链接起来,以便它们相互依赖,并且结果是您所布置的某种合并对象。

      关键(至少从我的学习中)是管道结束处的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()
          );
        }
      

      接口

      interface TodoItem {
        userId: number;
        id: number;
        title: string;
        completed: boolean;
      }
      
      interface User {
        id: number,
        name: string,
        username: string,
        address: object,
        phone: string;
        website: string;
        company: object;
      }
      
      interface SomeMergedObject {
        todoItem: TodoItem;
        user: User;
      }
      

      【讨论】:

      • 查看mergedObject的接口...不应该todoItem输入TodoItem[]
      • 在本例中,我只是返回待办事项并获取用户(通过 Todo.UserId)并合并两个用户/待办事项对象。因此,结果实际上是SomeMergedObject[],但您完全可以将其更改为TodoItem[] 的返回类型。我只是选择了一个合并的对象,因为这就是你正在做的事情。如果您查看 stackblitz,就会发现其中有一个完整的工作示例。可能需要一秒钟来获取数据,因为它正在执行大量 HTTP 请求。
      • 我的意思是, SomeMergedObject.todoItem 在我的问题中实际上应该是一个数组(todoItems)作为“请求”。每个“SomeMergedObject”可能有 0 个或多个“todoItem”
      • 你当然可以这样改变它。你可以用任何你喜欢的方式组成一个对象。你是说你本质上不是试图将两个不同的响应相互映射,而是试图将它们合并到一个对象{ allResponsesForResponse1: [ &lt;response1&gt;, ... ], allResponsesForResponse2: [&lt;response2&gt;, ...] }
      猜你喜欢
      • 2018-09-15
      • 2018-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2016-09-14
      • 1970-01-01
      • 2011-12-04
      相关资源
      最近更新 更多