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

时间:2019-03-07 16:53:38

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

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

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同步更改的数据。

这可能是什么原因?

2 个答案:

答案 0 :(得分:0)

根据documentation on billing

  

最低查询费用

     

您每次查询至少要读取一份文档   执行,即使查询没有返回结果。

因此,如果查询命中服务器,则会至少读取一次。

此外,在“收听查询结果”部分:

  

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

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

如果您的帐单未正确加起来,并且有一个可重现的示例,任何人都可以运行,则应contact Firebase support directly并提供这些详细信息。

答案 1 :(得分:0)

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

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

编写一个新的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中,将侦听器添加到写入最后一项更新时间的实时数据库路径。触发更新事件时,请再次读取项目并更新内存缓存。将项目更新时间存储在android共享的首选项中,以便在下次更新事件触发时,检查RTDB的更新时间是否高于保存的时间,并且仅在RTDB更新时间高于保存的时间时再次读取项目。