首页 > 解决方案 > Firestore 查询未获取最新数据

问题描述

我在 Angular 中做了一个路由保护,在允许访问该路由之前检查 firestore 中的某个值。

一旦 HTTP 云功能完成,该组件就会被路由到。此云函数在名为 的 firestore 文档中创建一个对象agreement,然后路由监听该对象中的状态,以决定是否允许访问。但我们遇到的问题是,可能有 9/10 次,守卫似乎认为该agreement对象在文档中不存在,因此引发错误。(虽然我可以在 Firestore 中看到协议对象!)。

我已经记录了流程,它正确地记录在订阅中,然后在警卫中,所以我知道 HTTP 函数在尝试路由和调用警卫类之前已经完成。

这是守门员:

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    this.tenancyOffer$ = this._tenancyOffer.getTenancyOfferById(route.params.offerId).get({source: 'server'})).valueChanges();
    
    return this.tenancyOffer$.pipe(
      map((tenancyOffer) => {
        if (tenancyOffer.status === 'incomplete'
          && tenancyOffer.agreement.status === 'incomplete') {
          return true;
        } else {
          this._router.navigate(['/' + Landlord.base, Landlord.manage.base, Landlord.manage.applications.base, route.params.propId, Landlord.manage.applications.summary, route.params.offerId]);
        }
      })
    );
  }

GetTenancyOfferById:

this.tenancyOfferCollection = afs.collection<any>('tenancy_offers');

getTenancyOfferById(id: string) {
  return this.tenancyOfferCollection.doc(id);
}

错误来自这部分:tenancyOffer.agreement.status === 'incomplete',说TypeError: Cannot read property 'status' of undefined.

我正在调用的 HTTP 函数在这里,在订阅中路由到该组件:

  landlordAcceptReferences() {
    this.hasAcceptedRefs = true;
    this.processingAcceptRefs = true;
    this._references.landlordAcceptReferences(this.offerId).pipe(
      finalize(() => {
        this.processingAcceptRefs = false;
      })
    ).subscribe(e => {
      console.log({e});
      this.dref.close();
      this._toastr.success(`You have accepted tenant references`);
      this._router.navigate(['../../', Landlord.manage.applications.agreement.base, this.offerId], {relativeTo: this._activatedRoute});
    }, () => this.hasAcceptedRefs = false);
  }

我将云函数的响应作为整个 firestore 文档,并且其中包含已记录的协议对象console.log({e});。然后我在警卫中记录(之后)文档的值,它不存在,即使这是我再次调用 firestore 的地方?

有没有人知道为什么getTenancyOfferById(route.params.offerId)守卫中的功能没有从firestore返回此文档的最新版本,即使云功能需要在订阅中路由之前结束?

标签: javascriptangularfirebasegoogle-cloud-firestorerxjs

解决方案


I guess this.tenancyOfferCollection = afs.collection<any>('tenancy_offers'); is defined somewhere in your service. If this is true, the collection will be loaded as soon as your application is loaded.

I recommend to store tenancy_offers values in your service and read it from your guard.

Service:

export class YourService {

  private tenancyOfferMap: Map<string, any> = new Map();

  constructor(
    private afs: AngularFirestore,
  ) {
    afs.collection<any>('tenancy_offers').snapshotChanges()
      .subscribe( actions => {
        actions.map( action => {
          this.tenancyOfferMap.set(action.payload.doc.id, action.payload.doc.data());
        });
      });
  }

  getTenancyOfferById(id: string) {
    return this.tenancyOfferMap.get(id);
  }

}

Guard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    const tenancyOffer = this.yourService.getTenancyOfferById(route.params.offerId);
    if (tenancyOffer.status === 'incomplete'
      && tenancyOffer.agreement.status === 'incomplete') {
      return true;
    } else {
      return this._router.navigate(['/' + Landlord.base, Landlord.manage.base, Landlord.manage.applications.base, route.params.propId, Landlord.manage.applications.summary, route.params.offerId]);
    }
  }

推荐阅读