firebase 如何确定Firestore快照是否来自服务器?

kq4fsx7k  于 2022-11-17  发布在  其他
关注(0)|答案(2)|浏览(162)

我的应用程序在内存中存储Firestore文档的副本。当数据被给定的客户端更改时,它首先更新它自己的内存副本,然后将这些相同的更新写入Firebase。

function updateDoc(docPath, changes) {
  updateInMemoryDocWithChanges(changes);

  app.firebase.db.doc(docPath).update(updates);
}

这些文档可能会同时被其他客户端更改。为了捕获这些更改,我们使用onSnapshot({ includeMetadataChanges: true}, ...)监听这些文档的更改,仅当hasPendingWritesfalse时更新内存中的副本:

function handleSnapshot(doc) {
  // local write just occurred
  if (doc.metadata.hasPendingWrites) return;

  updateInMemoryObject(doc.data())
}

问题
在慢速连接中,接收hasPendingWrites: falseonSnapshot事件时可能会有明显的延迟。因此会发生以下操作顺序,但由于延迟,客户端会临时更新为过时的数据。

  1. updateDoc()
    1.快照,hasPendingWrites=true(已忽略)
    1.进行了另一个更改,再次调用了updateDoc()
    1.快照,hasPendingWrites=false,来自步骤1中写入的更新。内存中的副本已更新,* 覆盖步骤3中所做的更改!*
    1.快照,hasPendingWrites=true,包含步骤3中的更新(已忽略)
    1.过了一会儿..
    1.快照,hasPendingWrites=false,包含步骤3中更新内存中副本已更新
    结果,客户端在使数据在7中重新出现之前看到一些令人不安的数据丢失。
    我想简单地忽略本地客户端更改导致的快照通知,但我能看到的唯一方法是将hasPendingWrites=truehasPendingWrites=false的快照匹配,也许是同一个文档?看起来很难看,容易出错。
    什么是正确的处理方式?
falq053o

falq053o1#

若要确定DocumentSnapshotMap服务器上数据库的目前状态,请检查docSnapshot.metadata.fromCache。如果此属性为true,则值来自本机快取,可能不是最新的。如果为false,则保证值随服务器更新。
这些性质对我来说是紧密相连的,我(目前)对自己解释为:

  • hasPendingWrites指示是否存在对此文档的本地更改,这些更改尚未发送到服务器/尚未由服务器处理。
  • fromCache表示这个文档可能是陈旧的。我认为这个属性名在这里有点不合适,因为它的值比加载快照的位置更能表明数据的新鲜度。
jvlzgdj9

jvlzgdj92#

这种情况下的解决方案是实现某种形式的数据版本控制。例如,添加一个整数version属性,每次修改对象时都会递增该属性。拒绝使用比内存中副本更旧的版本进行的任何更新。您的流将变为:

  1. updateDoc()(内存中=1)
    1.快照,hasPendingWrites=true(已忽略)(快照=1)
    1.进行另一个更改,再次调用updateDoc()(内存中=2)
  2. snapshot,'hasPendingWrites=false来自步骤1中写入的更新。*(in-memory=2,shapshot=1)*更新被拒绝,因为内存版本〉快照版本
  3. snapshot,hasPendingWrites=true,包含步骤3中的更新(已忽略)(snapshot=2)
    1.过了一会儿..
  4. snapshot,hasPendingWrites=false,包含步骤3中的更新。*(内存中=2,快照=2)*内存中副本已更新,因为内存版本〈=快照版本

相关问题