【问题标题】:Using MergeMap with the array of data received from another observable - RxJs Angular将 MergeMap 与从另一个 observable 接收的数据数组一起使用 - RxJs Angular
【发布时间】:2023-04-02 15:30:02
【问题描述】:

我有一个 fetchDrives 方法,它会返回一个 observable,订阅时会返回一个驱动器列表

this.fetchDrives(points).subscribe(drives => {
     console.log(drives);
});

假设我订阅的驱动器阵列看起来像这样

[ {driveId: 1}, {driveId: 2}, {driveId: 3} ]

现在我需要一个一个地使用 driveId 并通过将 driveId 传递给每个 api 调用来进行三个调用(三个调用,因为驱动器数组的长度为 3)。我需要一次将一个 driveId 传递给下面的方法,并且获取 lat 和 lon 并将三个调用的结果存储在一个数组中。

this.getLatLong(driveId).subscribe( res => console.log(res))

res 将包含像{ lat: 12, lon: 54 } 这样的对象

我不想进行两次订阅,有没有一种方法可以使用 Rxjs 运算符,并使用以前的 observable 的结果通过一次订阅来实现这一点,循环遍历驱动器数组并对 getLatLong 方法进行三次调用使用mergeMap 作为调用顺序无关紧要,并将这三个调用的结果存储在一个数组中?

我尝试使用扫描运算符循环但未能使用它来获得所需的输出

提前感谢您的帮助:)

【问题讨论】:

    标签: javascript angular rxjs rxjs6 rxjs-pipeable-operators


    【解决方案1】:

    如果请求的顺序无关紧要,您可以使用 RxJS forkJoin 方法同时进行调用。一旦源 observable (this.fetchDrives(points)) 发出,我还使用 switchMap 运算符来切换 observable。试试下面的

    locations: any;
    
    this.fetchDrives(points).pipe(
      switchMap((drives) => {
        let source = Object.create(null);
        for (let i = 0; i < drives.length; i++) {
          source[drives[i]['driveId']] = this.getLatLong(drives[i]['driveId']);
        }
        return forkJoin(source);
      })
    ).subscribe(
      response => {
        this.locations = response;
      },
      error => {
        // handle error
      }
    );
    

    变量locations 的格式为

    // 'driveId': { lat: 12, lon: 54 }
    
    {
      '1': { lat: 12, lon: 54 },
      '2': { lat: 12, lon: 54 },
      '3': { lat: 12, lon: 54 }
    }
    

    更新:对象数组输出

    要从forkJoin 返回一个对象数组,您可以发送一个可观察对象数组作为参数。例如。 forkJoin([obs1, obs2, ...])。在前面的例子中,我们发送一个对象作为参数(forkJoin({'name1': obs1, 'name2': obs2, ...}),所以输出也将是一个对象。

    locations: any = [];
    
    this.fetchDrives(points).pipe(
      switchMap((drives) => {
        return forkJoin(drives.map(drive => this.getLatLong(drive['driveId'])));
      })
    ).subscribe(
      response => {
        this.locations = response;
      },
      error => {
        // handle error
      }
    );
    

    locations 的格式为

    [
      { lat: 12, lon: 54 },
      { lat: 12, lon: 54 },
      { lat: 12, lon: 54 }
    ]
    

    【讨论】:

    • 我忽略了forkJoin 函数参数中的一个关键部分。我发送的是一组对象而不是一个对象。我已经编辑了答案。请尝试新版本。
    • Michael 想要的输出是一个对象数组,我相信 forkJoin 会做到这一点
    • 我已经更新了答案。在这种情况下,您可以使用forkJoin(drives.map(drive =&gt; this.getLatLong(drive['driveId'])))。请看看它是否适合你。
    【解决方案2】:

    如果我正确理解了您的问题,您希望展平驱动器阵列以迭代每个驱动器,然后进行 API 调用以获取每个驱动器 lat lon。

    您可以使用 mergeAllmergeMap 运算符实现这样的目的。
    您的代码应如下所示:

    fetchDrives().pipe(
      mergeAll(), // Flatten the drives array
      mergeMap(drive => getLatLong(drive)) // Get each drive { lat, lon }
    ).subscribe(console.log)
    

    您可以在this stackblitz 中运行完整示例

    【讨论】:

    • 它在订阅中打印了三次控制台,我只想用一个包含 lat lon 的对象数组来拥有它一次
    猜你喜欢
    • 1970-01-01
    • 2018-03-20
    • 2019-01-23
    • 2020-03-28
    • 2021-10-21
    • 2021-07-26
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多