首页 > 解决方案 > 在 firestore 中删除数组的成员时,我遵循的 observable 将使用结果数组中的未定义值进行更新

问题描述

我有以下功能。第一个更新 firestore 数据库以从 db 对象的数组中删除一个值。

removeGuardianFromFamily(guardian: string, familyId: string) {
    return this.afs.collection('family')
      .doc(familyId)
      .update({
        guardians: firestore.FieldValue.arrayRemove(guardian)
      }).then(() => { // Need to remove family from guardians family doc
        return this.removeFamilyFromUsersFamDoc(guardian, familyId);
      }).catch(() => {
        return { success: false }
      })
  }

接下来的功能,获取family doc,获取所有family信息(我已经包含了抓取数据时使用的接口)。

export interface FamilyInfo {
    familyId: string;
    moderatingGuardian: string;
    guardians: string[];
    okToReadKids: string[];
    familyName: string;
    kids: string[];
    isSearchable: boolean;
}

export interface FamilyInfoWithoutId {
    moderatingGuardian: string;
    guardians: string[];
    okToReadKids: string[];
    familyName: string;
    kids: string[];
    isSearchable: boolean;
}

getFamiliesDoc() {
    return this.authservice.user$.pipe(
      switchMap(user => {
        if (user) {
          return this.afs.collection('families')
            .doc(user.uid)
            .collection('myfamilies')
            .doc('myFamiliesDoc')
            .valueChanges();
        } else {
          return of(null);
        }
      }));
  }

getAllMyFamilies() {
    return this.getFamiliesDoc().pipe(
      tap((familiesDoc) => console.log("This is families doc in getAllMyFamilies", familiesDoc)),
      switchMap((fdoc: FamiliesDoc) => {
        // here we fetch all family data
        let familyDataDocs = fdoc.families.map(f => {
          return this.afs.doc(`family/${f}`).snapshotChanges().pipe(
            map((doc) => {
              return { familyId: doc.payload.id, ...doc.payload.data() as FamilyInfoWithoutId } as FamilyInfo;
            }));
         })
        return familyDataDocs.length ? combineLatest(familyDataDocs) : of([]);
      }),
      tap((families: FamilyInfo[]) => console.log("This is families in getAllMyFamilies AFTER WITH ALL FAM DATA", families)),);

  }

我在 getAllMyFamilies() 中观察到问题。在第一次加载时,对象完美加载,并反映了数据库中的值。但是,当您停留在同一页面上时,如果数据库发生更改,例如调用 removeGuardianFromFamily(),就会出现问题。该对象最初说:​</p>

familyName: "Day"
familyId: "famId"
guardians: Array [ undefined ]
isSearchable: true
kids: Array [ undefined ]
moderatingGuardian: "modGuard"
okToReadKids: Array [ undefined ]

但是 observable 然后重新触发,并且对象显示完整的数组并带有正确的信息,但是此时前端已经更新并且未定义的值是显示的值。

然后我想,我们如何检查未定义的值并仅在未定义时才显式设置它们。所以我做了以下事情:

hasUndefinedInArray(arr: string[]) {
    let hasUndefined = false;
    for (let mem of arr) {
      if (mem === undefined) {
        hasUndefined = true;
        break;
      }
    }
    return hasUndefined;
  }
  getAllMyFamilies() {
    return this.getFamiliesDoc().pipe(
      tap((familiesDoc) => console.log("This is families doc in getAllMyFamilies", familiesDoc)),
      switchMap((fdoc: FamiliesDoc) => {
        // here we fetch all family data
        let familyDataDocs = fdoc.families.map(f => {
          return this.afs.doc(`family/${f}`).snapshotChanges().pipe(
            tap((doc) => console.log("This is doc.payload.data() in families in getAllMyFamilies IN THE MIDDLE *******************************************", doc.payload.data())),
            map((doc: Action<DocumentSnapshot<FamilyInfoWithoutId>>) => {
              if (!this.hasUndefinedInArray(doc.payload.data().guardians)
                 && !this.hasUndefinedInArray(doc.payload.data().okToReadKids) && !this.hasUndefinedInArray(doc.payload.data().kids)) {
                let guardArray = [];
                let okToReadKidsArray = [];
                let kidsArray = [];
                for (let guard of doc.payload.data().guardians) {
                  if (guard !== undefined) {
                    guardArray.push(guard);
                  }
                }   
                for (let ok of doc.payload.data().okToReadKids) {
                  if (ok !== undefined) {
                    okToReadKidsArray.push(ok);
                  }
                }   
                for (let kid of doc.payload.data().kids) {
                  if (kid !== undefined) {
                    kidsArray.push(kid);
                  }
                }
                
                const famInfo: FamilyInfo = {
                  familyId: doc.payload.id,
                  moderatingGuardian: doc.payload.data().moderatingGuardian,
                  guardians: guardArray,
                  okToReadKids: okToReadKidsArray,
                  familyName: doc.payload.data().familyName,
                  kids: kidsArray,
                  isSearchable: doc.payload.data().isSearchable
                }
                return famInfo;
              }
            }),
            tap((familyInfo) => console.log("This is familyInfo in families in getAllMyFamilies IN THE MIDDLE AFTER *******************************************", familyInfo)),);
         })
        return familyDataDocs.length ? combineLatest(familyDataDocs) : of([]);
      }),
      tap((families: FamilyInfo[]) => console.log("This is families in getAllMyFamilies AFTER WITH ALL FAM DATA", families)),);

  }

这表明从 db 的初始拉取是成功的,并且没有数组具有来自以下行的未定义成员:

return this.afs.doc(`family/${f}`).snapshotChanges().pipe(
            tap((doc) => console.log("This is doc.payload.data() in families in getAllMyFamilies IN THE MIDDLE *******************************************", doc.payload.data())),

但是,在此之后:

 tap((familyInfo) => console.log("This is familyInfo in families in getAllMyFamilies IN THE MIDDLE AFTER *******************************************", familyInfo)),);

可以观察到,在初始更新时,FamilyInfo 对象中的每个数组都有一个未定义的值,如上所示。有什么策略可以解决这个问题吗?

标签: angularfirebasegoogle-cloud-firestore

解决方案


推荐阅读