即使启用了持久性,只有一个文档被修改后,Firestore查询会再次(从数据库)读取所有文档

时间:2018-01-28 18:29:35

标签: firebase google-cloud-firestore

预期行为:我认为当文档的某个字段被修改时,查询将只返回该文档,因此它只被视为1次读取。假设我查询了一个包含n个文档的集合,我希望它可以读取初始状态,如果稍后修改文档,那么只会从数据库中再次读取该文档,从而导致总共读取n + 1个。

我看到的内容 最初是n读取,并且只要一个文档被修改,无论离线持久性是否被加入,n都会读取;导致2n次读取所有" fromCache:false "元数据。

  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/subdocl‌​lection"); 
  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"元数据,即从数据库中读取。如果刷新查询但文档全部相同,则唯一一次从缓存中读取数据。

2 个答案:

答案 0 :(得分:2)

当您使用onSnapshot()请求集合(或查询)的快照时,对文档的任何更改都将导致整个快照发送到您的回调。所以,看到每个文件都是正常的。

如果该快照中的任何文档可能来自本地缓存,那就是您将收到的数据,并且它不会被视为读取。 Android和iOS客户端默认启用本地缓存。

对于Web客户端,它不一样。请read the documentation了解:

  

对于网络,默认情况下会禁用离线持久性。要启用   持久化,调用enablePersistence方法。 Cloud Firestore的   会话之间不会自动清除缓存。因此,如果   您的Web应用程序处理敏感信息,请务必询问用户   如果他们在启用持久性之前在可信设备上。

另外,下面的说明:

  

重要提示:对于网络,离线持久性是一项实验性功能   只有Chrome,Safari和Firefox网络支持   浏览器。此外,如果用户打开指向的多个浏览器选项卡   相同的Cloud Firestore数据库和启用的离线持久性,   Cloud Firestore仅在第一个选项卡中正常工作。

因此,在您的情况下,如果您没有启用本地缓存,则可能会在每次更改时收取所有返回文档的读取费用。

如果您想知道DocumentSnapshot是否来自缓存,您可以使用fromCache中的metadata属性。

答案 1 :(得分:1)

我注意到了这种行为,并做了一些研究:实际上一切都很好!

当您收听N个文档的集合时,将对N个初始状态执行N次读取,然后按预期在文档更改时进行1次读取。 youtube videothe 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"]]]