Angular firestore onSnapshot执行两次

Angular firestore onSnapshot执行两次,angular,firebase,google-cloud-firestore,Angular,Firebase,Google Cloud Firestore,我的firestore onSnapshot()函数被调用了两次 let user = firebase.firestore().collection('users').doc(userID).onSnapshot ({ next: (documentSnapshot: firebase.firestore.DocumentSnapshot) => { this.userArray.push(documentSnap

我的firestore onSnapshot()函数被调用了两次

let user = firebase.firestore().collection('users').doc(userID).onSnapshot
({                    
    next: (documentSnapshot: firebase.firestore.DocumentSnapshot) =>
    {
         this.userArray.push(documentSnapshot as User);
         console.log(documentSnapshot);
         //here
    },
    error: (firestoreError: firebase.firestore.FirestoreError) =>
    {
         console.log(firestoreError);
         //here
    }
});
我也尝试过在//here注释中加入user()来订阅,但没有效果


如何修改,使函数只执行一次,即每次只推送一个用户对象,而不是两次。

如果需要一次响应,请使用.get()方法进行承诺

firebase.firestore().collection('users').doc(userID).get().then(snap => {
  this.userArray = [...this.userArray, snap.doc);
});

但是,我建议使用(因为我维护了库,所以完全有偏见)。它使处理普通的角度+火基任务变得更加容易

我不知道这是否与你的问题有关。如果一个人正在使用

firebase.firestore.FieldValue.serverTimestamp()
要给文档加上时间戳,OnSnapshot将触发两次。这似乎是因为,当您向数据库添加新文档时,onSnapshot将启动,但serverTimestamp尚未运行。几毫秒后,serverTimestamp将运行并更新您的文档=>onSnapshot将再次启动

我想在onSnapshot火灾之前增加一点延迟(比如说0,5秒左右),但我找不到这样做的方法

您还可以为onCreate事件创建服务器端函数,我相信这会解决您的问题。也许您的userArray.push-action更适合在服务器端执行


更新:要了解有关
serverTimestamp()的行为以及它触发侦听器两次的原因的更多信息,请阅读本文:。此外,官方文件指出:

执行写入操作时,在将数据发送到后端之前,将用新数据通知侦听器

在本文中,有两种建议的解决方案,其中一种是使用
快照的
metadata
属性来查找
metadata.hasPendingWrites
的布尔值是否为真(它告诉您正在查看的快照尚未写入服务器)或假

例如,在您的情况下,您可以检查
hasPendingWrites
是否为false,然后推送对象:

if(!documentSnapshot.metadata.hasPendingWrites){
//此代码仅在数据写入服务器后执行
this.userArray.push(documentSnapshot作为用户);
console.log(documentSnapshot);
}
在更一般的示例中,代码如下所示:

firestore.collection(“MyCollection”)
.onSnapshot(快照=>{
if(snapshot.metadata.hasPendingWrites){
//本地更改尚未写入后端
}否则{
//已将更改写入后端
}
});
文档中提供的另一种有用方法如下:

如果您只想知道写入何时完成,可以侦听完成回调,而不是使用
hasPendingWrites
。在JavaScript中,通过附加.then()回调来使用从写操作返回的承诺

我希望这些资源和各种方法将帮助任何试图找到解决方案的人

参考文献:


在我的例子中,当从客户端设置
FieldValue.serverTimestamp()
时,第一个通知包含相关字段的空值;第二个通知包含服务器时间戳值。最后,我使用了一个云函数来执行相同的逻辑,它为我解决了双重触发问题。触发器
firebase.firestore.FieldValue.serverTimestamp()
在此处调用internallySame thing.metadata.fromCache的值更改也会触发更新。这难道不符合使用
onSnapshot
的目的吗?据我所知,
get()
不会侦听更改。