12

我正在尝试映射一个可观察对象,从我返回的可观察对象中获取一个值,然后将该值输入另一个可观察对象并返回该结果。这是我到目前为止所拥有的:

  getJobsByUser(user: User): Observable<Job[]> {
    return this.getUsersGroupsAsObservable(user.uid, 'contacts').map(groups => {
      groups.map(group => {
        this.getJobsbyGroup(group.id);
      });
    });

  getJobsbyGroup(groupId: string): Observable<Job[]> {
    return this.afs
      .collection<Job>('jobs', ref => ref.where(`group.${groupId}`, '==', true))
      .valueChanges();
  }

  getUsersGroupsAsObservable(
    userId: string,
    type: string = 'users',
  ): Observable<Group[]> {
    return this.afs
      .collection<Group>('groups', ref =>
        ref.where(`${type}.${userId}`, '==', true),
      )
      .valueChanges();
  }

问题是打字稿表明我的 getJobsByUser 函数将返回一个可观察的类型:void。当我在我的模板上输出它时,我什么也没有得到或未定义。我觉得我需要使用 switchMap 但我对 rx/js 有点模糊。我不确定如何返回 Job[] 类型的 Observable

更新:在@Pranay Rana 的帮助下,我现在返回数组,并且可以获得这样的第一个值:

  getJobsByUser(user: User): Observable<Job[]> {
    return this.getUsersGroupsAsObservable(user.uid, 'contacts').pipe(
      mergeMap(groups => {
        // returns an array of groups - we need to map this
        return this.getJobsbyGroup(groups[0].id); // works with the first value - do we need another map here?
      }),
    );
  }

更新 2:我已经设法从 firestore 取回一些数据,但它发出多个 observables 而不是组合流:

this.fb.getUsersGroupsAsObservable(user.uid, 'contacts')
   .switchMap(groups => {
      return groups.map(group => this.fb.getJobsbyGroup(group.id));
   })
    .subscribe(res => {
       console.log(res);
       // this emits multiple observables rather than one
       this.job$ = res;
    });
4

2 回答 2

15

以下方法在以下位置详细讨论:处理并行多个请求的方法

下面的方法利用mergemap

getJobsByUser(user: User) {
     return this.getUsersGroupsAsObservable(user.uid, 'contacts').pipe(
       mergeMap(group => this.getJobsbyGroup( group.id))
     );
}

callingfunction(){
  const requests = this.getJobsByUser(this.user);
  requests.subscribe(
  data => console.log(data), //process item or push it to array 
  err => console.log(err));
}

你也可以利用forkJoin

getJobsByUser(user: User) {
         return this.getUsersGroupsAsObservable(user.uid, 'contacts').pipe(
           map(group => this.getJobsbyGroup( group.id))
         );
    }

    callingfunction(){
      const requests = forkJoin(this.getJobsByUser(this.user));
      requests.subscribe(
      data => console.log(data), //process item or push it to array 
      err => console.log(err));
    }
于 2018-06-12T05:14:25.370 回答
7

好的,首先您return在函数中缺少两个语句getJobsByUser(如下所示,大写RETURN

getJobsByUser(user: User): Observable<Job[]> {
    return this.getUsersGroupsAsObservable(user.uid, 'contacts').map(groups => {
      RETURN groups.map(group => {
        RETURN this.getJobsbyGroup(group.id);
      });
    });

或者,更优雅一点:

getJobsByUser(user: User): Observable<Job[]> {
    return this.getUsersGroupsAsObservable(user.uid, 'contacts')
      .map(groups => groups.map(group => this.getJobsbyGroup(group.id)));
}

现在我们需要将结果展平,因为如果我做对了,1user有很多groups,每个group很多jobs,你希望你的最终结果只是 aJob[]jobs所有groupsuser.

您可以使用多个运算符来展平结果,例如switchMap,或concatMap。这是一个例子:

getJobsByUser(user: User): Observable<Job[]> {
    return this.getUsersGroupsAsObservable(user.uid, 'contacts')
      .concatMap(groups => groups)
      .concatMap(group => this.getJobsbyGroup(group.id))
      .concatMap(jobs => jobs)
      .toArray();
}

每一行的内容是这样的:

  1. 给我groups一个user// 返回Observable<Group[]>
  2. 展平Group[]// 返回的结果Observable<Group>
  3. 给我jobs一个group// 返回Observable<Job[]>
  4. 展平job[]// 返回的结果Observable<Job>
  5. 将所有事件收集Job到一个具有Job[]
于 2018-06-12T10:02:29.567 回答