我的应用程序在内存中存储Firestore文档的副本。当数据被给定的客户端更改时,它首先更新它自己的内存副本,然后将这些相同的更新写入Firebase。
function updateDoc(docPath, changes) {
updateInMemoryDocWithChanges(changes);
app.firebase.db.doc(docPath).update(updates);
}
这些文档可能会同时被其他客户端更改。为了捕获这些更改,我们使用onSnapshot({ includeMetadataChanges: true}, ...)
监听这些文档的更改,仅当hasPendingWrites
为false
时更新内存中的副本:
function handleSnapshot(doc) {
// local write just occurred
if (doc.metadata.hasPendingWrites) return;
updateInMemoryObject(doc.data())
}
问题
在慢速连接中,接收hasPendingWrites: false
的onSnapshot
事件时可能会有明显的延迟。因此会发生以下操作顺序,但由于延迟,客户端会临时更新为过时的数据。
updateDoc()
1.快照,hasPendingWrites=true
(已忽略)
1.进行了另一个更改,再次调用了updateDoc()
1.快照,hasPendingWrites=false
,来自步骤1中写入的更新。内存中的副本已更新,* 覆盖步骤3中所做的更改!*
1.快照,hasPendingWrites=true
,包含步骤3中的更新(已忽略)
1.过了一会儿..
1.快照,hasPendingWrites=false
,包含步骤3中更新内存中副本已更新
结果,客户端在使数据在7中重新出现之前看到一些令人不安的数据丢失。
我想简单地忽略本地客户端更改导致的快照通知,但我能看到的唯一方法是将hasPendingWrites=true
与hasPendingWrites=false
的快照匹配,也许是同一个文档?看起来很难看,容易出错。
什么是正确的处理方式?
2条答案
按热度按时间falq053o1#
若要确定
DocumentSnapshot
Map服务器上数据库的目前状态,请检查docSnapshot.metadata.fromCache
。如果此属性为true
,则值来自本机快取,可能不是最新的。如果为false
,则保证值随服务器更新。这些性质对我来说是紧密相连的,我(目前)对自己解释为:
hasPendingWrites
指示是否存在对此文档的本地更改,这些更改尚未发送到服务器/尚未由服务器处理。fromCache
表示这个文档可能是陈旧的。我认为这个属性名在这里有点不合适,因为它的值比加载快照的位置更能表明数据的新鲜度。jvlzgdj92#
这种情况下的解决方案是实现某种形式的数据版本控制。例如,添加一个整数
version
属性,每次修改对象时都会递增该属性。拒绝使用比内存中副本更旧的版本进行的任何更新。您的流将变为:updateDoc()
(内存中=1)1.快照,
hasPendingWrites=true
(已忽略)(快照=1)1.进行另一个更改,再次调用
updateDoc()
(内存中=2)1.过了一会儿..