【问题标题】:Chaining rxjs 6 observables with nested array用嵌套数组链接 rxjs 6 个 observables
【发布时间】:2020-02-14 16:49:40
【问题描述】:

我必须对 API 执行 3 个依赖请求。

  1. 第一个检索用户 ID 的数组。
  2. 第二个必须遍历用户 ID 的数组,并为每个检索与用户相关的项目 ID 数组。
  3. 第三个必须遍历项目 ID 的数组并检索与项目相关的数据。

我想要这样的结果:

[{'username': 'richard', projects: [{"id": 1, "name": "test"}]}, ...]

但我完全被 mergeMap、forkJoin 等所困扰。

我尝试过的东西:

getUserTeamMembers(): Observable<any> {
return this.http.get(`${environment.serverUrl}/user/profil`).pipe(
  mergeMap((teamUsers: any) =>
    this.http.get(
      `api/user/${teamUsers.data._id}/team`
    )
  ),
  mergeMap((teamUsers: any) =>
    forkJoin(
      ...teamUsers.data.map((user: any) =>
        this.http.get(`api/user/${user.id}`)
      )
    )
  ),
  map((res: any) =>
    res
      .map((user: any) => {
        if (user.data) {
          return {
            firstname: user.data.local.firstname,
            lastname: user.data.local.lastname,
            email: user.data.local.email,
            projects: user.data.local.projects,
            language: user.data.local.lang
          };
        }
      })
      .filter((user: any) => user !== undefined)
  ),
  tap(t => console.log(t)),
  catchError(err => throwError(err))
);}

我尝试了很多东西,但我不知道在哪里填充我的项目数组,这些项目目前只包含 id,而不是数据相关:

[{'username': 'richard', projects: ['id1', 'id2']}, ...]

【问题讨论】:

    标签: rxjs observable


    【解决方案1】:

    已经做了一个类似的例子,希望它清楚这个想法。

    当然没有使用 http 而是使用 of 将其本地化

    并将最终结果存储在一个名为results的数组中

    我们有一个获取所有用户列表的来源,另一个给定用户 ID 的来源将返回该用户项目 ID 的列表projectList,最后一个提供一个项目 ID 的来源将返回其详细信息(projcectsDetails)

        let users = of([ 1, 2, 3 ])
        let projectsList = (userId) => of([ userId, userId*2 ]) 
        let projectsDetails = (projectId) => of({ id: projectId, details: `details about ${projectId}` })
    
    
        let results = [];
    
        users
        .pipe(
          tap(users => {
            users.forEach(userId => results.push({ userId, projects: [] }));
    
            return users
          }),
          switchMap(users => forkJoin(users.map(userId => projectsList(userId)))),
          switchMap(projectsArray => forkJoin(
              projectsArray.map(
                oneProjectArray => 
                forkJoin(oneProjectArray.map(projectId => projectsDetails(projectId)))
              )
            )
          ),
          tap(projectDetailsArray => {
            projectDetailsArray.forEach((projectsArray, index) =>{
              results[index]['projects'] = [ ...projectsArray ]
            })
          })
        )
        .subscribe(() => console.warn('final',results))
    
    

    解释

      1- initalize the result array from the given users
      [ 
       { userId: X, projcts: [] }, 
       { userId: Y, projcts: [] }, 
        ....
      ]
    
      2- for each give users we want the projects ids he/she has
      so the first switchMap will return (in order)
      [
       [ 1, 2, 3, ...] project ids for the first user,
       [ 8, 12, 63, ...] project ids for the second user,
       ...
      ]
    
      3- in the second switchMap we iterate over the previous array
      (which is an array that each item in it is an array of projects ids)
    
      so we needed two forkJoin the outer will iterate over each array of projects ids(the big outer 
      array previously mentioned)
      the inner one will iterate over each single project id and resolve it's observable value(which is the
      project details)
    
      4- finally in the tap process we have an array of array like the 2nd step but this time each
      array has the projects details and not the projects ids
    
      [
       { userId:1, projects: [ { id:1, details: 'details about 1' }, { id:2, details: 'details about 2' }]},
       { userId:2, projects: [ { id:2, details: 'details about 2' }, { id:4, details: 'details about 4' }]},
       { userId:3, projects: [ { id:3, details: 'details about 3' }, { id:6, details: 'details about 6' }]}
      ]
    

    【讨论】:

    • 优秀的答案和很好的解释,但我认为水龙头会炸毁答案是不必要的。只是一个意见:)
    • 感谢您的宝贵时间,我现在有一个错误,当我执行最后 2 次 forkJoin 时,我的数据库被正确调用,但我的所有请求都被取消了,所以当我最终点击时,没有任何内容结果。
    • @amerej 对不起,我的错。 switchMap 将取消之前的请求或事件,因此请尝试使用 mergeMap 而不是第二个 switchMap,如果可行,请告诉我更新答案。
    • @LouayAlosh 是的,它适用于合并映射,但现在,我找不到创建结果数组的方法,如果我在点击中返回结果,它会返回良好的结果,但次数他在最后一个mergeMap中找到了结果,如果我不返回结果,它会返回一个未定义的数组:(
    • @amerej 问题是最后一次点击中的 projectDetailsArray 是否按您需要的顺序返回您想要的内容?
    猜你喜欢
    • 1970-01-01
    • 2019-03-17
    • 2017-08-10
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-06
    • 1970-01-01
    相关资源
    最近更新 更多