Невозможно выполнить рекурсивный запрос с использованием Rx JS 6 и оператора расширения (Angular, Firebase & Observables) - PullRequest
0 голосов
/ 10 апреля 2020

Я слежу за этим вопросом , чтобы создать запрос, который извлекает один случайный элемент из коллекции Firebase в приложении Angular 9, используя AngularFire.

Решение отлично работает, и я получаю ожидаемый результат, кроме случаев, когда запрос возвращает 0 результатов. Если это произойдет, я хочу повторить запрос, меняя некоторые параметры, пока не получу один элемент, и только потом верну наблюдаемую, на которую можно подписаться в других сервисах. Я изучаю, как использовать Observables и Rx JS 6 операторов, и я думаю, что мне нужен оператор expand. Однако я не могу предотвратить выход expand из рекурсивного l oop, пока не достигну желаемого результата.

Это мой код:

random-query. service.ts

  fetchDocumentoAleatorio(coleccionPath: string): Observable<any> {
    const IdRandom = this.db.createId();
    return this.consultaAleatorio(coleccionPath, '>=', IdRandom)
      .pipe(expand((document: any) => document === null ? this.consultaAleatorio(coleccionPath, '<=', IdRandom) : EMPTY
        ), // I expect to repeat the query here changing '>=' to '<=' and using the same randomly generated Id
        map((document) => { // The recursive loop never takes place since the map operator triggers even if consultaAleatorio() returns null one single time, sending that result to the subscribers
            return publicacion.payload.doc.data();
          }
        ));
  }



consultaAleatorio(path: string, operador: any, idRandom: string): Observable<any> {
    return this.db
      .collection(path, ref => {
        let query: firebase.firestore.CollectionReference | firebase.firestore.Query = ref;
        query = query.where('random', operador, idRandom);
        query = query.orderBy('random');
        query = query.limit(1);
        return query;
      }).snapshotChanges()
      .pipe(map((arrayDatos: any) => {
        if (arrayDatos && arrayDatos.length) {
          return arrayDatos[0];
        } else {
          return null; // It indeed reaches this point if the query returns empty results
        }
      }));
  }

Если какой-либо другой сервис использует этот код, он делает это следующим образом:

subscriber-example-service.ts

 private firebaseSubscriptions: Subscription [] = [];
  publicacionAleatoriaSubject = new Subject<IpublicacionMiniatura>();
  private publicacionAleatoria: IpublicacionMiniatura;

constructor(
    private db: AngularFirestore,
    private randomQueryService: RandomQueryService) {
  }
  fetchPublicacionAleatoria(): void {
    this.firebaseSubscriptions.push(this.randomQueryService.fetchDocumentoAleatorio('publicaciones-meta')
      .pipe(map((publicacion) => {
          return {
           //processes data
              };
            })
      )
      .subscribe((publicacionAleatoria: IpublicacionMiniatura) => {
          this.publicacionAleatoria = publicacionAleatoria;
          this.publicacionAleatoriaSubject.next(this.publicacionAleatoria);
        }
      ));

В сумме:

  • Рекурсивный l oop никогда не выполняется, поскольку оператор map срабатывает, даже если consultaAleatorio() возвращает null один раз, отправка этого результата подписчикам
  • Когда я подписываюсь на это Observable в других службах, он работает гладко и, как и ожидалось, за исключением описанного случая, поэтому я думаю, что проблема заключается в моем непонимании того, как обрабатывать expand оператор для достижения того, что мне нужно.

Заранее благодарим за ваше время.

1 Ответ

0 голосов
/ 10 апреля 2020

Вы можете использовать retryWhen, как показано ниже:

 .pipe(map((arrayDatos: any) => {
        if (arrayDatos && arrayDatos.length) {
          return arrayDatos[0];
        } else {
          throw new Error(); //  this causes it to be catched by retryWhen
        }
      }), retryWhen(errors=>errors.pipe(delay(100))); // retry after 100ms

Stackblitz

Edit : исправлен образец и добавлен стек-блиц.

...