如何通过第二次调用将 Observable 与信息合并

How to consolidate an Observable with informations by a second calls

出于教育目的,我正在尝试调用检索帖子列表的服务,对于每个 post,我想再次调用此服务以获取评论列表.

我正在使用来自 https://jsonplaceholder.typicode.com/posts

的数据

首先是我为此服务提取的模型:

export interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
  comments: PostComment[];
}

export interface PostComment {
  postId: number;
  id: number;
  name: string;
  email: string;
  body: string;
}

这是我目前的状态。我的目标是 Observable<Post> 正确填充 属性 comments

export class PostCommentsCombination implements OnInit {
  constructor(private http: HttpClient) {}

  posts$?: Observable<Post[]>;

  ngOnInit(): void {
    this.posts$ =this.http.get<Post[]> ('https://jsonplaceholder.typicode.com/posts/').pipe(
      switchMap((posts) =>
        posts.map((post) =>
          this.http.get<PostComment[]>(`https://jsonplaceholder.typicode.com/posts/${post.id}/comments`).pipe(
            map((comments) => {
              post.comments = comments;
              return post;
            })
          )
        )
      )
    );
  }
}

但是它说不能将Observable<Observable<Post>>转换成Observable<Post[]>。我不能怪他,但我不确定如何解决这个问题?

posts.map((post) => ...

基本上是获取每个 post 并将其映射到一个 Observable。所以你最终得到了一个 Observables 数组。你想要做的是解析数组中的每个 Observable 以获得你想要的输出。如果您熟悉 promises,您希望 rxjs 等效于 Promise.all,它本质上是 forkJoin - 请参阅此 post

可以 forkJoin 请求评论,更新 post.comments 字段和 return post 返回:

this.posts$ = this.http
  .get<Post[]>('https://jsonplaceholder.typicode.com/posts/')
  .pipe(
    switchMap(posts =>
      forkJoin(
        posts.map(post =>
          this.http
            .get<PostComment[]>(`https://jsonplaceholder.typicode.com/posts/${post.id}/comments`)
            .pipe(map(comments => {
              post.comments = comments;
              return post;
            }))
        )
      )
    )
  );

Demo

我会尝试这样的事情:

ngOnInit(): void {

  const postsUrl = 'https://jsonplaceholder.typicode.com/posts/';

  this.posts$ = this.http.get<Post[]>(postsUrl).pipe(
    map(posts => posts.map(post =>
      this.http.get<PostComment[]>(`${postsUrl}${post.id}/comments`).pipe(
        map(comments => ({...post, comments}))
      )
    )),
    switchMap(postObservables => forkJoin(postObservables))
  );
  
}