Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 使用RxJS从多个API调用构建数据_Angular_Http_Rxjs_Observable_Mergemap - Fatal编程技术网

Angular 使用RxJS从多个API调用构建数据

Angular 使用RxJS从多个API调用构建数据,angular,http,rxjs,observable,mergemap,Angular,Http,Rxjs,Observable,Mergemap,我试图更好地理解如何使用RxJS操作符来解决我遇到的一个特定问题。我实际上有两个问题,但它们非常相似 我从一个API端点/API/v3/folders/${folderId}/documents抓取了一堆文档,我用函数设置了服务,并处理所有的身份验证等 但是,此文档对象数组没有description属性。为了获得描述,我需要对上一次调用中的每个文档调用/api/v3/documents/${documentId}/。我的文档界面如下所示: export interface Document {

我试图更好地理解如何使用RxJS操作符来解决我遇到的一个特定问题。我实际上有两个问题,但它们非常相似

我从一个API端点
/API/v3/folders/${folderId}/documents
抓取了一堆文档,我用函数设置了服务,并处理所有的身份验证等

但是,此文档对象数组没有description属性。为了获得描述,我需要对上一次调用中的每个文档调用
/api/v3/documents/${documentId}/
。我的文档界面如下所示:

export interface Document {
  id: number;
  name: string;
  description: string;
}
我想我需要使用
mergeMap
等待并获取文档,了解如何将描述添加到我的
Document
界面并返回整个内容,但是我很难获得最终结果

getDocuments(folderId: number) {
    return this.docService.getDocuments(folderId, this.cookie).pipe(
      map(document => {
        document; // not entirely sure what to do here, does this 'document' carry over to mergeMap?
      }),
      mergeMap(document => {
        this.docService.getDocument(documentId, this.cookie)
      }) // possibly another map here to finalize the array? 
    ).subscribe(res => console.log(res));
  }
这可能看起来有点重复,但我发现的任何帖子都没有100%为我澄清问题

非常感谢在理解如何正确使用第二次调用中的数据并将其全部打包方面提供的任何帮助。多谢各位

感谢@BizzyBob,这里是最后的解决方案,并提供了编辑和解释:

  getDocuments(folderId: number) {
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
      'Context': this.cookie$
    });
    return this.docService.getDocuments(folderId, this.cookie$).pipe(
      mergeMap(documents => from(documents)),
      mergeMap(document => this.http.get<IDocument>(
        this.lcmsService.getBaseUrl() + `/api/v3/documents/${document.id}`,
        { headers: headers }
      ).pipe(
        map(completeDoc => ({...document, description: completeDoc.description}))
      )),
      toArray()
    ).subscribe(docs => {
      this.documents = docs;
      console.log(this.documents);
    }
    )
  }
getDocuments(folderId:number){
const headers=新的HttpHeaders({
“内容类型”:“应用程序/json”,
“上下文”:this.cookie$
});
返回此.docService.getDocuments(folderId,this.cookie$).pipe(
合并映射(文档=>from(文档)),
mergeMap(document=>this.http.get(
this.lcmsService.getBaseUrl()+`/api/v3/documents/${document.id}`,
{headers:headers}
).烟斗(
映射(completeDoc=>({…文档,描述:completeDoc.description}))
)),
toArray()
).订阅(文档=>{
本文件=单据;
console.log(this.documents);
}
)
}

由于某种原因,我无法从第二个服务订阅中调用
pipe()
,因此我不得不在那里调用
http.get
。错误是“不能在类型订阅上使用管道()”,这有点混乱,因为我在第一个订阅上使用了
pipe()
。我将此更改应用于我的服务功能,该功能更新了一个行为主题,并且工作正常。谢谢

由于必须调用文档/{id}端点才能获取描述, 对于每个文档,您最终都会调用rest作为您拥有的文档数量

mergeMap
返回一个可观察对象,并在外部可观察对象上订阅它。(与switchMap相比,使内部订阅保持活动状态)

Rxjs
from
获取一个数组,并通过按顺序发出数组中的每个项来返回一个可观测值。

因此,为了实现您的目标,我们可以同时使用这两种方法:

(对不起,我使用手机时的格式设置不正确)

我假设docService.getDocuments返回一个文档数组

getDocuments(folderId: number) { 
    return this.docService.getDocuments(folderId, this.cookie).pipe(
      mergeMap((allDocumentsArray)=> {
             return from(allDocumentsArray).pipe(
               mergeMap((document) =>        
                   this.docservice.getDocument(document).pipe(
                        map(doc) => {...document,description})),//maps the document with document.description
     toArray(),//combines the returned values to an array
    ).subscribe(res => console.log(res));
我建议您阅读他们文档中关于mergemap的内容。
并在使用之前进行测试,因为我还没有测试过。

有几种不同的方法可以从多个api调用合成数据

我们可以:

  • 使用
    from
    将每个项目分别发送到流中
  • 使用
    mergeMap
    订阅辅助服务呼叫
  • 使用
    toArray
    在所有单个调用完成后发出数组
我们还可以利用
forkJoin

  getDocuments() {
    return this.docService.getDocuments().pipe(
      switchMap(basicDocs => forkJoin(
        basicDocs.map(doc => this.docService.getDocument(doc.id))
      ).pipe(
        map(fullDocs => fullDocs.map((fullDoc, i) => ({...basicDocs[i], description: fullDoc.description})))
      )),
    );
  }
这是一张工作票

也可以考虑将流定义为变量<代码>文档$,而不是方法>代码> GETDICONTIONS()/<代码>


这回答了你的问题吗@fridoo这确实有点帮助,谢谢是的,这是同一个问题。请注意,如果您想保证最终的
docs
数组中项目的顺序与
this.docService.getDocuments(folderId,this.cookie$)发出的数组中项目的顺序相同,则必须使用
forkJoin
方法。啊,谢谢!我将用实际数据做一些更彻底的测试。希望一切都能顺利进行。再次感谢!谢谢你,你的评论让我走上了正轨!非常感谢你!你对各个部分的解释真的帮助了我@coderrr22让我走上了正确的道路,但你的回答最终让我更加坚定。我从未使用过
from()
,也从未正确使用过第二个
pipe()
map()。非常感谢。将用最终的解决方案编辑我的问题。另外,如果您有时间,您能解释一下为什么我无法使用
pipe()
在第二次订阅时,没有进行
get
调用,而不是使用服务中的方法?您无法在第二次调用中访问第一次调用的数据的原因是它们不是同一个闭包的一部分。添加额外的“.pipe()”会将两个调用的结果放在同一范围内,以便您可以访问这两个调用。查看此答案(以及问题)了解更多详细信息:
  getDocuments() {
    return this.docService.getDocuments().pipe(
      switchMap(basicDocs => forkJoin(
        basicDocs.map(doc => this.docService.getDocument(doc.id))
      ).pipe(
        map(fullDocs => fullDocs.map((fullDoc, i) => ({...basicDocs[i], description: fullDoc.description})))
      )),
    );
  }
  documents$ = this.docService.getDocuments().pipe(
    mergeMap(basicDocs => from(basicDocs))
    mergeMap(basicDoc => this.docService.getDocument(basicDoc.id).pipe(
      map(fullDoc => ({...basicDoc, description: fullDoc.description}))
    ))
    toArray()
  );