Как мне реорганизовать вложенные подписки с помощью switchmap или других опций rxjs при работе с наблюдаемыми Firestore?

#angular #google-cloud-firestore #rxjs

#angular #google-cloud-firestore #rxjs

Вопрос:

Я новичок в angular, и мне нужно подняться на холм, прежде чем я пойму, что происходит, и работа с наблюдаемыми из Firestore ставит меня в тупик. Мне нужно поле ID из одного вызова службы, чтобы получить данные из следующих двух вызовов службы, избегая при этом страшного undefined. Как нам это сделать?

 this.myMatch = this.route.snapshot.paramMap.get("createdMatchIdKey");

this.golfDataService.GetSelectedMatch(this.myMatch)
  .subscribe(result => {
    this.match = resu<
    this.setupTable(this.match.matchCourseId);
    this.golfDataService.GetSelectedGolfCourse(this.match.matchCourseId)
      .subscribe(result => {
        this.course = resu<
        console.log(this.course);
      })
    this.golfDataService.GetSelectedCourseTees(this.match.matchCourseId)
      .pipe(takeUntil(this.onDestroy))
      .subscribe(result => {
        this.tees = resu<
        console.log(this.tees);
        for (var i = 0; i < this.tees.length; i  ) {
          this.golfDataService.GetHoles(this.tees[i].teeIdKey)
            .subscribe(result => {
              console.log(this.teeHoleInfo);
              this.teeHoleInfo.push(result);
              console.log(this.match);
            })
        }
      })
  })
  

Ответ №1:

В общем, «способ» RxJS заключается в том, чтобы попытаться сохранить ваш конвейер как можно более чистым (без внешних побочных эффектов). Вы, конечно, можете использовать tap для установки своих глобальных переменных по пути, но я думаю, что это лучше с точки зрения тестирования, модульности и расширения — возможности не делать ничего из этого, пока вы не получите все свои данные.

Этот подход создает объект вида:

 {
  match: any,
  course: any, 
  tees: any[],
  holes: any[]
}
  
  • совпадение — это результат golfDataService.GetSelectedMatch
  • конечно, это результат golfDataService.GetSelectedGolfCourse
  • tees — это результат golfDataService.GetSelectedCourseTees
  • отверстия — это объединенный результат целого ряда вызовов golfDataService.GetHoles ( golfDataService.GetHoles для каждой записи в tees должен быть один вызов)

Конечный результат получает подписку, а затем там вызываются все консоли и присваивания вашим глобальным переменным.

 this.myMatch = this.route.snapshot.paramMap.get("createdMatchIdKey");

this.golfDataService.GetSelectedMatch(this.myMatch).pipe(
  mergeMap(match =>
    zip(
      this.golfDataService.GetSelectedGolfCourse(match.matchCourseId),
      this.golfDataService.GetSelectedCourseTees(match.matchCourseId)
    ).pipe(
      take(1),
      map(([course, tees])=> ({
        match,
        course,
        tees
      }))
    ),
    mergeMap(({match, course, tees}) => 
      zip(
        ...tees.map(tee => this.golfDataService.GetHoles(tee.teeIdKey))
      ).pipe(
        take(1),
        map(holes => ({
          match,
          course,
          tees,
          holes
        }))
      )
    )
  )
).subscribe(({match, course, tees, holes}) => {
  this.match = match;
  this.setupTable(this.match.matchCourseId);
  this.course = course;
  console.log(this.course);
  this.tees = tees;
  console.log(this.tees);
  this.teeHoleInfo = holes;
  console.log(this.teeHoleInfo);
});
  

Следует отметить, что fork(...) это, вероятно, лучше, чем zip(...).pipe(take(1)) , но работает только при запуске observable, который, как вы уверены, будет завершен.