firebase - Firestore onSnapshot 更新事件是否由于本地客户端设置?
问题描述
简单版: 当我在 Firestore 中注册 onSnapshot 时,有没有办法知道我是否是推送更新的客户端?
详细版本:
当一个网页打开时,它会注册一个 onSnapshot 回调到一个名为 的 Firestore 集合notes
。然后将集合下载并存储在本地数组var notes = []
中。
var window.notes = []
let notesRef = refs.db.collection('notes')
notesRef.onSnapshot(querySnapshot => {
querySnapshot.docChanges.forEach((docChange) => {
switch (docChange.type) {
case 'added':
notes.push(docChange.doc.data())
break
}
})
}
然后我们在本地更新便笺并将其推送到数据库。
notes[0] = 'changed contents'
firestore.notesRef.doc(0).set(notes[0])
这会将注释发送到 firestore,在远程数据库中更新它,然后因为我们已注册到onSnapshot
该notes
集合,我们将触发该事件并获得modified
更改。
let notesRef = refs.db.collection('notes')
notesRef.onSnapshot(querySnapshot => {
querySnapshot.docChanges.forEach((docChange) => {
switch (docChange.type) {
case 'added':
notes.push(docChange.doc.data())
break
case 'modified':
// ********** We end up here!!! ***********
// Probably want to do:
notes[docChange.doc.id] = docChange.doc.data()
break
}
})
}
有没有办法检测同一个客户端是否调用了set
触发modified
docChange 的客户端?
关键是:如果用户自己进行了更改,那么他们不关心更改广告,我们应该忽略它。如果其他用户进行了更改,则应让该用户选择是否要更新其本地版本。
根据我的经验,firestore.notesRef.doc(0).set(notes[0])
调用时需要一些时间才能从服务器接收更新。如果本地用户在这段时间内再次修改了注释但尚未将其推送到服务器,那么他们的更改将丢失(被服务器版本覆盖 - 他们上次发送到服务器的版本)。这本质上是一种竞争条件。
那么,当我在 Firestore 中注册 onSnapshot 时,有没有办法知道我是否是推送更新的客户端?
解决方案
您可以通过以下方式查看它是本地更改还是远程更改:
docChange.doc.metadata.hasPendingWrites
如果hasPendingWrites
为真,则更新的来源是本地的。本地缓存已更新,对服务器的写入仍处于挂起状态。如果hasPendingWrites
为 false,则更新的来源是远程的。
onSnapshot
在此代码段中查看如何使用它:
let notesRef = refs.db.collection('notes')
notesRef.onSnapshot(querySnapshot => {
querySnapshot.docChanges.forEach((docChange) => {
switch (docChange.type) {
case 'added':
notes.push(docChange.doc.data())
break
case 'modified':
// ********** New Code ***********
let source = docChange.doc.metadata.hasPendingWrites ? 'Local' : 'Server'
if (source === 'Server') {
notes[docChange.doc.id] = docChange.doc.data()
} else {
// Do nothing, it's a local update so ignore it
}
// ********** New Code End ***********
break
}
})
}
推荐阅读
- angularjs - Angularjs:使用 ng-if 过滤 ng-repeat
- fullcalendar - Fullcalendar 使用资源作为选择菜单的功能
- javascript - 为什么我收到无法读取未定义的属性“状态”?
- javascript - Redux 商店没有更新
- powershell - 使用带有局部变量和 Invoke-Command 的 add 方法
- android - Android Studio 构建失败:Android 资源链接失败,未能创建目录 C:\tmp\
- javascript - 如何根据 Bokeh 中先前的多选选择向绘图添加参考曲线
- sql-server - OpenRowset 与链接服务器
- anylogic - 如何将到达时间间隔平均为 10 秒
- react-native - 使用 react-native-snap-carousel 输出多个不同的元素?