如何避免使用缓存进行不必要的 Firestore 读取

How to avoid unnecessary Firestore reads with Cache

我有一个按日期排序的行程数据列表(大集)。

现有行为

我将所有行程数据存储到 SqlLite Db 中。对于添加的每个新数据,我都会收到一个 fcm 通知,并且我使用上次更新时间概念仅同步新添加的数据。这样,每当 cx 打开应用程序时,他总是会从我的数据库中读取数据,从而节省 readnetwork 操作。

我怎样才能使用 Firestore 实现同样的效果?

需要考虑的几个问题:

Firestore get() always tries to get the data first from SERVER, even if I add CACHE to my query, how can I sync only the updated document?

根据有关 enable offline data 的官方文档:

For Android and iOS, offline persistence is enabled by default.

因此,要使用离线持久性,您无需对代码进行(“添加”)任何更改即可使用和访问 Cloud Firestore 数据。

另外根据关于 Query 的 get() 方法的官方文档:

By default, get() attempts to provide up-to-date data when possible by waiting for data from the server, but it may return cached data or fail if you are offline and the server cannot be reached. This behavior can be altered via the Source parameter.

所以这是正常行为。从 2018-06-13 (16.0.0 SDK) 开始,现在可以指定我们要从中获取数据的来源。我们可以借助 DocumentReference.get(Source source) and Query.get(Source source) 方法来实现这一点。

如您所见,我们现在可以将源作为参数传递给 DocumentReferenceQuery,这样我们就可以强制从 server only 检索数据, cache only 或尝试服务器并回退到缓存。

所以这样的事情现在是可能的:

yourDocRef.get(Source.SERVER).addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
    @Override
    public void onSuccess(DocumentSnapshot documentSnapshot) {
        //Get data from the documentSnapshot object
    }
});

在这种情况下,我们强制仅从服务器检索数据。如果你想强制只从缓存中检索数据,你应该作为参数传递给 get() 方法,Source.CACHE。更多信息 here。我还写了一篇文章,可以帮助理解更清晰的概念:

如果你只想得到updated documents,你可以view changes between snapshots。官方文档中的一个例子是:

db.collection("cities")
    .whereEqualTo("state", "CA")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(@Nullable QuerySnapshot snapshots,
                @Nullable FirebaseFirestoreException e) {
        if (e != null) {
            Log.w(TAG, "listen:error", e);
            return;
        }

        for (DocumentChange dc : snapshots.getDocumentChanges()) {
            switch (dc.getType()) {
            case ADDED:
                Log.d(TAG, "New city: " + dc.getDocument().getData());
                break;
            case MODIFIED:
                Log.d(TAG, "Modified city: " + dc.getDocument().getData());
                break;
            case REMOVED:
                Log.d(TAG, "Removed city: " + dc.getDocument().getData());
                break;
            }
        }

        }
    });

看到每个特定情况的 switch 语句了吗?第二种情况将帮助您只获取更新后的数据。

In my Recyler View I want the data to be order by a field date not by lut(last-modified-time)

在这种情况下,您应该创建一个查询,允许您按特定日期 属性 对结果进行排序。假设您的数据库结构如下所示:

Firestore-root
   |
   --- items (collection)
        |
        --- itemId (document)
             |
             --- date: Oct 08, 2018 at 6:16:58 PM UTC+3
             |
             --- //other properties

类似的查询将帮助您实现这一目标:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionRefference itemsRef = rootRef.collection("items");
Query query = itemsRef.orderBy("date", Query.Direction.ASCENDING);

也是一种推荐的方式,您可以通过这种方式向 Cloud Firestore 数据库添加时间戳。

With FireStore Snapshot Listener i can't query such a large record set.

哦,是的,你可以。根据这个 answer,Firebase 可以有效地循环遍历数十亿个项目。此答案适用于 Firebase 实时数据库,但同样的原则适用于 Cloud Firestore。

您只需添加要检索的数据源即可

firestore.collection("yourCollection").get({source:"cache"})