【问题标题】:Firestore database read count increases even when data is fetched from cache即使从缓存中获取数据,Firestore 数据库读取计数也会增加
【发布时间】: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同步了变化的数据。

这可能是什么原因?

【问题讨论】:

    标签: android firebase firebase-realtime-database google-cloud-firestore


    【解决方案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/…),但我还不知道如何使它工作..
      猜你喜欢
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多