预期行为:我认为当文档的某个字段被修改时,查询将只返回该文档,因此它只被视为1次读取。假设我查询了一个包含n个文档的集合,我希望它可以读取初始状态,如果稍后修改文档,那么只会从数据库中再次读取该文档,从而导致总共读取n + 1个。
我看到的内容
最初是n读取,并且只要一个文档被修改
myCollection:
doc1 :
value: "some string"
...
docn:
value: "some text"
稍后我通过控制台更改一个文档的值:
myCollection:
doc1 :
value: "changed to other value"
...
docn:
value: "some text"
但我在查询快照中再次获取所有n个文档。无论我是否可以使用" s.docChanges"来观察更改,似乎快照都包含所有n个文档。
const someCollectionRef = firebase.firestore().collection("collection/document/subdocllection");
someCollectionRef.onSnapshot(s => {
var d = [];
s.forEach(doc => {
d.push(doc.data()));
//fromCache is always false even when one document is
//modified it seems that all documents are read from db again
console.log(`metadata is ` , doc.metadata);
}
//d seems to have all my documents even when only 1 is modified
});
启用离线持久性没有区别。我在启用离线持久性的情况下测试了相同的示例,没有区别!修改文档仍会导致所有文档都被" fromCache:false"元数据,即从数据库中读取。如果刷新查询但文档全部相同,则唯一一次从缓存中读取数据。
答案 0 :(得分:2)
当您使用onSnapshot()请求集合(或查询)的快照时,对文档的任何更改都将导致整个快照发送到您的回调。所以,看到每个文件都是正常的。
如果该快照中的任何文档可能来自本地缓存,那就是您将收到的数据,并且它不会被视为读取。 Android和iOS客户端默认启用本地缓存。
对于Web客户端,它不一样。请read the documentation了解:
对于网络,默认情况下会禁用离线持久性。要启用 持久化,调用enablePersistence方法。 Cloud Firestore的 会话之间不会自动清除缓存。因此,如果 您的Web应用程序处理敏感信息,请务必询问用户 如果他们在启用持久性之前在可信设备上。
另外,下面的说明:
重要提示:对于网络,离线持久性是一项实验性功能 只有Chrome,Safari和Firefox网络支持 浏览器。此外,如果用户打开指向的多个浏览器选项卡 相同的Cloud Firestore数据库和启用的离线持久性, Cloud Firestore仅在第一个选项卡中正常工作。
因此,在您的情况下,如果您没有启用本地缓存,则可能会在每次更改时收取所有返回文档的读取费用。
答案 1 :(得分:1)
我注意到了这种行为,并做了一些研究:实际上一切都很好!
当您收听N个文档的集合时,将对N个初始状态执行N次读取,然后按预期在文档更改时进行1次读取。 youtube video和the documentation的计费方面对此都有很好的描述。
陷阱是fromCache元数据。当您收到文档更改的更新时,所有其他未更改的文档均具有 fromCache:false,但它们实际上来自缓存,如Firebase开发人员在this SO answer中所述!>
fromCache元数据仅在脱机持久性范围内为true,当从本地缓存中进行了最初的N次读取时。文档从服务器接收数据后,它将设置fromCache:false,并且永远不会返回到fromCache:true。命名令人不安,但似乎按预期进行。
测试代码:
<html>
<body>
<script src="/__/firebase/7.22.1/firebase-app.js"></script>
<script src="/__/firebase/7.23.0/firebase-firestore.js"></script>
<script src="/__/firebase/init.js"></script>
<script>
firebase.firestore().enablePersistence().then(() => {
const collectionRef = firebase.firestore().collection("/fruits");
collectionRef.onSnapshot({includeMetadataChanges: true}, snapshot => {
console.log("=================== snapshot received ===================");
snapshot.forEach(doc => {
console.log(`doc ${doc.id}, metadata:`, doc.metadata);
});
});
});
</script>
</body>
</html>
我使用Firebase控制台修改了一个文档,并且在我的浏览器的控制台中,当长轮询请求终止时,它表明一个文档已转移:
15
[[14,["noop"]]]370
[[15,[{
"documentChange": {
"document": {
"name": "projects/xxx/databases/(default)/documents/fruits/apricot",
"fields": {
"color": {
"stringValue": "red"
}
},
"createTime": "2020-10-13T08:14:19.649748Z",
"updateTime": "2020-10-13T14:16:09.991161Z"
},
"targetIds": [
2
]
}
}
]]]122
[[16,[{
"targetChange": {
"resumeToken": "CgkI+bft8+Cx7AI=",
"readTime": "2020-10-13T14:16:09.991161Z"
}
}
]]]15
[[17,["noop"]]]