Как заполнить наблюдаемый другим наблюдаемым и вернуть наблюдаемый

#typescript #rxjs #observable

#typescript #rxjs #наблюдаемый

Вопрос:

Я работаю над проектом rxjs и использую json-сервер в качестве поставщика базы данных. Я застрял в получении одной коллекции, которую мне нужно заполнить другой коллекцией.

У меня есть совпадение коллекции и турнир коллекции. Внутри сопоставления коллекций у меня есть только tournamentId, но мое сопоставление классов также содержит экземпляр турнира.

 class Match{
    id:number;
    ...
    tournamentId:number;
    tournament: Tournament;
}

class Tournament{
    id:number;
    ...
    name:String;
}
  

Мне нужно 2 вызова из базы данных. Сначала, чтобы получить все турниры, а затем, чтобы получить все матчи.

Мне нужно вернуть наблюдаемое совпадение, которое было заполнено турниром.

 get(): Observable<Match> {
    return Observable.create(obs => {
      tournamentService.get().pipe(toArray()).subscribe(tournaments => {//tournaments = [torunament1, tournament2]
        super.get().pipe(map(x => { let m = new Match(x); m.populateTournament(tournaments); obs.next(m); return m; })).subscribe(() => {
          obs.complete();
        });
      });
    });
  }
  

obs.complete() вызывается немедленно, поэтому я получаю только одно совпадение в созданном observable.
Я пытаюсь заполнить Match с помощью Tournament в канале map, а также отправить его как obs.next (m) там. Я тоже не знаю, разумно ли это.

tournamentService.get() и super.get() возвращают наблюдаемые для турнира и незаселенного матча соответственно (JS {object} с теми же атрибутами).

Как мне выполнить совпадения next() один за другим и после того, как все они будут отправлены абоненту, вызовите complete() ?

Ответ №1:

Вы не должны создавать свои собственные наблюдаемые, для этого уже существуют операторы, которые вы можете использовать. Я думаю, что mergeMap, switchMap и combineLatest все работают здесь.

Вы должны объединить эти две наблюдаемые:

   get(): Observable<Match> {
    return combineLatest([super.get(), tournamentService.get()]) // Combine both Observables when both emit
      .pipe(map(([match, tours])=> { // Destructuring array of emitted values
        let m = new Match(match);
        m.populateTournament(tours);
        return m; // Return match combined with tournaments
    }))
  }
  

Комментарии:

1. Подтверждено! Но все еще возникают проблемы. Tournaments — это observable, который запускается только один раз (это целый массив турниров), поскольку мне нужны все турниры в моем методе populateTournament().

2. Так в чем проблема? Вы получите все турниры, подобные этому.

3. Левый наблюдаемый выдает больше раз, чем правый наблюдаемый. super.get() остается. tournamentService.get().pipe(toArray()) является правильным. Поскольку мне не нужны турниры один за другим, мне нужны все они в массиве.

4. Я хочу сказать, что combineLatest ограничен observable, который излучается меньше. Поскольку один наблюдаемый является целым массивом (генерируется один раз), другой наблюдаемый ограничен и выдается только последнее (например, 15-е совпадение).

5. Управлял этим с помощью withLatestFrom pipe.

Ответ №2:

Мне также удалось решить проблему с помощью канала ‘withLatestFrom’.

  get(): Observable<Match> {
    let matchesObs = super.get();
    let tournamentsObs = tournamentService.get().pipe(toArray());

    return matchesObs.pipe(
      withLatestFrom(tournamentsObs),
      map(([m, t]) => {
        let match = new Match(m as Match);
        match.populateTournament(t as Tournament[]);
        return match;
      })
    );
  }