无法使用 RxJS 6 和扩展运算符进行递归查询(Angular、Firebase 和 Observables)
Unable to query recursively using RxJS 6 and expand operator (Angular, Firebase & Observables)
我正在关注 创建一个查询,该查询使用 AngularFire 从 Angular 9 应用程序中的 firebase 集合中检索一个随机项目。
解决方案工作正常,我得到了预期的结果,除非查询 returns 0 结果。如果发生这种情况,我想重复查询更改一些参数,直到我得到一个项目,然后才 return 一个可以在其他服务中订阅的可观察对象。我正在学习如何使用 Observables 和 RxJS 6 运算符,我认为 expand
运算符是我需要的。但是,在达到预期结果之前,我无法阻止 expand
退出递归循环。
这是我的代码:
随机-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
}
}));
}
如果任何其他服务使用此代码,它会这样做:
订阅者示例-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);
}
));
总之:
- 递归循环永远不会发生,因为即使
consultaAleatorio()
returns null
一次,map
运算符也会触发,并将结果发送给订阅者
- 当我在其他服务中订阅这个 Observable 时,除了描述的情况外,它工作顺利并且符合预期,所以我认为问题出在我对如何处理
expand
运算符以实现什么的误解我需要。
预先感谢您的宝贵时间。
您可以像下面这样使用 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。
我正在关注
解决方案工作正常,我得到了预期的结果,除非查询 returns 0 结果。如果发生这种情况,我想重复查询更改一些参数,直到我得到一个项目,然后才 return 一个可以在其他服务中订阅的可观察对象。我正在学习如何使用 Observables 和 RxJS 6 运算符,我认为 expand
运算符是我需要的。但是,在达到预期结果之前,我无法阻止 expand
退出递归循环。
这是我的代码:
随机-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
}
}));
}
如果任何其他服务使用此代码,它会这样做:
订阅者示例-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);
}
));
总之:
- 递归循环永远不会发生,因为即使
consultaAleatorio()
returnsnull
一次,map
运算符也会触发,并将结果发送给订阅者 - 当我在其他服务中订阅这个 Observable 时,除了描述的情况外,它工作顺利并且符合预期,所以我认为问题出在我对如何处理
expand
运算符以实现什么的误解我需要。
预先感谢您的宝贵时间。
您可以像下面这样使用 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。