即使从缓存中获取数据,Firestore 数据库读取计数也会增加

Posted

技术标签:

【中文标题】即使从缓存中获取数据,Firestore 数据库读取计数也会增加【英文标题】:Firestore database read count increases even when data is fetched from cache 【发布时间】:2019-07-29 15:36:18 【问题描述】:

我将一些数据存储在我的 android 应用程序在启动时加载的 firestore 中。我使用以下方法在应用程序启动时加载此数据。

FirebaseFirestore.getInstance().collection("users").document(ApplicationEx.getUserId()).collection("items").addSnapshotListener((queryDocumentSnapshots, e) -> 
    if (queryDocumentSnapshots != null) 
        LOGGER.info("items fetched. from cache: " + queryDocumentSnapshots.getMetadata().isFromCache());
        for (QueryDocumentSnapshot queryDocumentSnapshot : queryDocumentSnapshots) 
            items.add(queryDocumentSnapshot.toObject(Item.class));
        
    
);

当我重新启动应用程序时,可以看到数据是从缓存中获取的,因为queryDocumentSnapshots.getMetadata().isFromCache() 每次都返回 true。但是,当我检查 firebase 控制台时,我可以看到有时文档读取计数会增加。

行为不一致。当我连续多次重新启动应用程序时,读取计数大部分时间都不会增加。但是,如果我有几分钟没有使用该应用程序,然后再启动该应用程序,则大部分时间读取计数都会增加。

存储的数据没有变化,所以这不可能是由于android同步了变化的数据。

这可能是什么原因?

【问题讨论】:

【参考方案1】:

我联系了 Firebase 支持,根据他们的说法,这就是它在 Firestore 中的工作方式。即使项目在本地缓存,当监听器断开连接超过 30 分钟时,下一次 fetch 会从服务器读取所有文档。

我使用以下机制在一定程度上克服了我的问题。

编写一个新的 firebase 云函数来监听集合的写入。它将集合更新到实时数据库的时间写入。

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

exports.onItemModified = functions.firestore.document('users/userId/items/itemId').onWrite((change, context) => 
    return admin.database().ref('/users/' + context.params.userId + '/items-updated-at').set(Date.now());
);

在android中,在应用启动时,禁用网络,加载项目,然后再次启用网络。

FirebaseFirestore.getInstance().disableNetwork().addOnCompleteListener(task -> loadItems());

private void loadItems() 
    Utils.getFirestoreCollection(COLLECTION_NAME_ITEMS).get().addOnCompleteListener(task -> 
        //Cache loaded items in memory
        FirebaseFirestore.getInstance().enableNetwork();
    

在android中,添加一个监听器到实时数据库路径,最后一个item更新时间被写入其中。当更新事件被触发时,再次读取项目并更新内存缓存。将item更新时间存储在android shared preferences中,这样下次更新事件触发时,检查RTDB的更新时间是否高于保存时间,只有当RTDB更新时间高于保存时间时才再次读取item。

【讨论】:

【参考方案2】:

根据documentation on billing:

查询最低收费

您为每个查询读取一份文档的最低费用 执行,即使查询没有返回结果。

因此,如果查询到达服务器,您的查询将引发至少一次读取。

此外,在标题为“收听查询结果”的部分中:

如果监听器断开连接超过 30 分钟(例如, 如果用户离线),您将被收取阅读费用,就好像您有 发出了全新的查询。

这意味着,如果您的听众离开并在 30 分钟后回来(例如,如果应用程序是后台运行的,后来又被前台运行),那么您将再次为查询付费。

如果您认为计费计算不正确,并且您有一个任何人都可以运行的可重现示例,您应该 contact Firebase support directly 提供这些详细信息。

【讨论】:

感谢您的回答。因此,假设用户已经缓存了集合中的所有文档,并让应用程序关闭了几个小时。当用户打开应用程序时,不需要从服务器获取数据,因为本地缓存不是陈旧的。即使这样,这是否算作再次从服务器获取的所有文档? 正如我的回答所说,引用文档,您将至少阅读一次查询。本地缓存的状态与那个最小值无关。 我明白,但我的观察是读取计数不仅增加了 1,而且增加了集合中的总文档数。这是预料之中的事情吗? 如果没有精确的复制步骤,就无法说出您的情况。一般来说,如果您在计费或 Firebase 控制台方面遇到问题,您应该直接联系 Firebase 支持。 firebase.google.com/support/contact 是的,每次 SnapshotListener 连接时,如果断开连接的时间超过 30 分钟,您需要对查询中的每个文档进行读取。所以如果我有 1000 个文档,并且用户打开该应用程序白天 5 次(每次间隔超过 30 分钟),我将收取 5000 次阅读费用!不是所有的视频都让你相信..我找到了这个 (medium.com/firebase-tips-tricks/…),但我还不知道如何使它工作..

以上是关于即使从缓存中获取数据,Firestore 数据库读取计数也会增加的主要内容,如果未能解决你的问题,请参考以下文章

Firestore:仅当有更新时才从服务器获取数据,否则从缓存中获取

即使我禁用了持久性,Firestore 仍在从缓存中检索文档

有时我的云函数会从 Firestore 返回旧数据。是缓存问题吗?

即使文档中缺少请求的字段,如何安全地从 cloud-firestore 获取数据?

如何使用本地缓存并仅使用 Firestore 更新更改的文档?

Firestore - 使用缓存直到在线内容更新