使用 firebase 和 angular 的无限循环

Infinit loop with firebase and angular

我在使用 firebase 保存数据时遇到无限循环问题 this.db.collection('users').doc(this.useruid).update({Info: this.currentInfo})

private currentInfo:string[];
private useruid: string;
...
constructor(private AngularAuth: AngularFireAuth,
    private db:AngularFirestore) { }

...

sendInfo(text:string){
    this.useruid = this.AngularAuth.auth.currentUser.uid;
    this.db.collection('users').doc(this.useruid).snapshotChanges().subscribe(a=>{
      const data = a.payload.data() as {name:string, Info:string[]};
      data.Info.forEach(element => {
        this.currentInfo.push(element);
      });
      this.currentInfo.push(text);
      this.db.collection('users').doc(this.useruid).update({
        Info: this.currentInfo
      })...
    })
}

举个例子,假设我目前有 currentInfo = ["a","b","c"]text = "d",在 y 运行 方法 sendInfo( ) 之后, 我得到一个循环:["a","b","c","d","a","b","c","d","d","a","b","c","d","a","b","c","d","d","d"...] 等等。

要根据文档的当前值更新文档,use a transaction:

var userDocRef = collection('users').doc(this.useruid);

return db.runTransaction(function(transaction) {
    // This code may get re-run multiple times if there are conflicts.
    return transaction.get(userDocRef).then(function(userDoc) {
        if (!userDoc.exists) {
            throw "Document does not exist!";
        }

        const data = userDoc.data() as {name:string, Info:string[]};
        data.Info.forEach(element => {
          this.currentInfo.push(element);
        });
        this.currentInfo.push(text);

        transaction.update(userDocRef, { Info: this.currentInfo });
    });
}).then(function() {
    console.log("Transaction successfully committed!");
}).catch(function(error) {
    console.log("Transaction failed: ", error);
});

除了防止您当前拥有的无限循环外,这还可以防止多个用户在几乎同时更新文档时覆盖彼此的结果。

您可以使用 pipe 和 first 获取您需要的值,然后再次更新。

sendInfo(text: string) {
    this.useruid = this.AngularAuth.auth.currentUser.uid;
    this.db.collection('users').doc(this.useruid).valueChanges().pipe(first()).subscribe(a => {
        const data = a.payload.data() as {name:string, Info:string[]};
        data.Info.forEach(element => {
            this.currentInfo.push(element);
        });
        this.currentInfo.push(text);
    }
    this.db.collection('users').doc(this.useruid).update({
        Info: this.currentInfo
    })
}

rxjs的第一个方法用于获取一个observable发出的第一个值。之后,它取消订阅 observable。