Observable 中每个 id 的循环数组和 return 数据

Loop array and return data for each id in Observable

使用 RxJS v6 从循环中的每个项目的子集合中检索数据具有挑战性。无法迭代从 HTTP 调用中检索到的抛出数组。合并映射仅对需要对所有数组项执行此操作的单个项执行此操作。

我已经坚持了 3 天了。我已经尝试了一切。问题是新的管道语法虽然为您提供了组织代码的简洁方法,但没有简单的方法来循环抛出数据集合。无法使用 map javascript 函数,因为它在可观察范围之外并且项目 returned 未定义。在互联网上,我只能找到一个效果很好的单个 mergeMap 的基本示例。但是我需要使用 数组中的每个项目都带有 http 调用并将响应追加到同一对象。

我从第 3 方的两个端点开始,我无法控制它们。我嘲笑了一些例子API来说明。

端点 1 - Returns 所有项目 ID: http://localhost:3000/联系人

{
  "name": "test",
  "contact": [
    {
      "_id": "5c9dda9aca9c171d6ba4b87e"
    },
    {
      "_id": "5c9ddb82ca9c171d6ba4b87f"
    },
    {
      "_id": "5c9ddb8aca9c171d6ba4b880"
    }
  ]
}

端点 2 - Returns 单项信息: http://localhost:3000/contact/5c9dda9aca9c171d6ba4b87e

[
   {
     "_id": "5c9dda9aca9c171d6ba4b87e",
     "firstName": "Luke",
     "lastName": "Test",
     "email": "vgadgf@adsgasdg.com",
     "created_date": "2019-03-29T08:43:06.344Z"
   }
]

期望的结果 - 通过使用 RxJs v6+ return 嵌套数据可观察:

{
  "name": "test",
  "contact": [
    {
      "_id": "5c9dda9aca9c171d6ba4b87e".
      "relationship":  {
                         "_id": "5c9dda9aca9c171d6ba4b87e",
                         "firstName": "Luke",
                         "lastName": "Test",
                         "email": "vgadgf@adsgasdg.com",
                         "created_date": "2019-03-29T08:43:06.344Z"
                       }
    },
    {
      "_id": "5c9ddb82ca9c171d6ba4b87f",
      "relationship": {
                         "_id": "5c9ddb82ca9c171d6ba4b87f",
                         "firstName": "Name2",
                         "lastName": "Test2",
                         "email": "vgadgf@adsgasdg2.com",
                         "created_date": "2019-03-29T08:43:06.344Z"
                       }
    },
    {
      "_id": "5c9ddb8aca9c171d6ba4b880",
      "relationship": {
                         "_id": "5c9ddb8aca9c171d6ba4b880",
                         "firstName": "Name3",
                         "lastName": "Test3",
                         "email": "vgadgf@adsgasdg3.com",
                         "created_date": "2019-03-29T08:43:06.344Z"
                       }
    }
  ]
}

我只是在尝试使用 Javascript 循环时遇到错误,并且使用不同的运算符也没有给我太多帮助,因为问题在于 RxJs 中的循环。这是我制作的代码。请提供任何有用的建议或文档。

testService.service.ts

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {concatMap, map, mergeMap} from 'rxjs/operators';

@Injectable()
export class TestServiceService {

  constructor(
    private http: HttpClient
  ) { }

  public getCombinedData(): Observable<any> {
    return this.getMultipleRelationData()
      .pipe(
        map((result: any) => {
          result = result.contact;

          return result;
        }),
        mergeMap((fullResults: any) => {
          return fullResults[0].relationship = this.getSingleData(fullResults[0]._id);
        })
      );
  }

  public getSingleData(id): Observable<any> {
    return this.http.get('http://localhost:3000/contact/' + id);
  }

  public getMultipleRelationData(): Observable<any> {
    return this.http.get('http://localhost:3000/contact');
  }

}

我目前的结束数据看起来只是一个单一的项目。如果我只想打一个电话就太好了……但是它与上面描述的期望输出相去甚远。

  [
  {
    "_id": "5c9dda9aca9c171d6ba4b87e",
    "firstName": "Luke",
    "lastName": "Test",
    "email": "vgadgf@adsgasdg.com",
    "__v": 0,
    "created_date": "2019-03-29T08:43:06.344Z"
  }
]

使用嵌套的 mergeMapmap 是很有可能的。坚持使用 Observable 的一个关键方法是使用 from 函数将 contacts 数组扩展为一个 observable。然后使用 toArray 运算符收集数据。提供文档示例:

public getCombinedData(): Observable<any> {
  return this.getMultipleRelationData()
      .pipe(
          mergeMap((result: any) =>

              // `from` emits each contact separately 
              from(result.contact).pipe(
                  // load each contact
                  mergeMap(
                      contact => this.getSignleData(contact._id),
                      // in result selector, connect fetched detail 
                      (original, detail) => ({...original, relationship: detail})
                  ),
                  // collect all contacts into an array
                  toArray(),
                  // add the newly fetched data to original result
                  map(contact => ({ ...result, contact})),
              )
          ),
      );
}

编辑:结果选择器已弃用

里面的mergeMap,后面可以用一个map

public getCombinedData(): Observable<any> {
  return this.getMultipleRelationData().pipe(
      mergeMap((result: any) =>
          // `from` emits each contact separately
          from(result.contact).pipe(
              // load each contact
              mergeMap(
                  contact =>
                      this.getSignleData(contact._id).pipe(
                          map(detail => ({ ...contact, relationship: detail })),
                      ),
                  // collect all contacts into an array
                  toArray(),
                  // add the newly fetched data to original result
                  map(contact => ({ ...result, contact })),
              ),
          ),
      ),
  );
}

虽然 kvetis 的回答对你有用,但我实现的是这个,只是发布它是因为我觉得解决它很有趣。

  public getCombinedData(): Observable<any> {
    return this.getMultipleRelationData()
      .pipe(
        mergeMap((result: any) => {
          let allIds = result.contact.map(id => this.getSingleData(id._id));
          return forkJoin(...allIds).pipe(
            map((idDataArray) => {
              result.contact.forEach((eachContact, index) => {
                eachContact.relationship = idDataArray[index];
              })
              return result;
            })
          )
        })
      );
  }

这是针对您的问题的示例解决方案,我制作了虚拟 Observable。 https://stackblitz.com/edit/angular-tonn5q?file=src%2Fapp%2Fapi-calls.service.ts