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

Bik*_*ash 3 java android firebase firebaseui google-cloud-firestore

我有按日期排序的旅行数据(大集合)列表。

现有行为

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

我如何在Firestore中实现相同目标?

需要考虑的几个问题:

  • Firestore get()始终尝试首先从服务器获取数据,即使我将CACHE添加到查询中,我如何也只能同步已更新的文档
  • 在我的Recyler视图中,我希望按字段日期而不是lut(last-modified-time)对数据进行排序
  • 使用FireStore Snapshot Listener,我无法查询这么大的记录集。

Ale*_*amo 10

即使我将CACHE添加到查询中,Firestore get()始终始终尝试首先从SERVER获取数据,如何仅同步更新的文档?

根据有关启用离线数据的官方文档:

对于Android和iOS,默认情况下启用离线持久性。

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

同样根据有关Query的get()方法的官方文档:

默认情况下,get()尝试通过等待来自服务器的数据来尽可能地提供最新数据,但是如果您离线并且无法访问服务器,它可能会返回缓存的数据或失败。可以通过Source参数更改此行为。

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

正如你所看到的,我们现在可以作为参数传递给DocumentReference或给Query源,以便我们可以强制数据的检索从server onlychache only或尝试服务器,并回落到缓存中。

因此,现在可以进行如下操作:

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

在这种情况下,我们强制仅从服务器检索数据。如果您想强制仅从缓存中检索数据,则应将用作参数传递给get()方法Source.SERVER。更多信息在这里

如果只想获取updated documents,则可以查看快照之间的更改。官方文档中的示例为:

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;
            }
        }

        }
    });
Run Code Online (Sandbox Code Playgroud)

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

在我的Recyler视图中,我希望按字段日期而不是lut(last-modified-time)对数据进行排序

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

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

像这样的查询将帮助您实现此目的:

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

也是建议的一种向Cloud Firestore数据库添加时间戳的方法。

使用FireStore Snapshot Listener,我无法查询这么大的记录集。

哦,可以。根据此答案,Firebase可以有效遍历数十亿个项目。该答案适用于Firebase实时数据库,但相同的原理也适用于Cloud Firestore。

  • “为什么 FirebaseUI-Firestore 在分页的情况下不支持实时更新?” 你应该问另一个问题。同时,**[this](/sf/ask/3551937091/)** 是一种推荐的方式,您可以通过组合查询游标对查询进行分页使用 limit() 方法。我还建议您看一下这个 **[video](https://www.youtube.com/watch?v=KdgKvLll07s)** 以获得更好的理解。 (2认同)
  • 如果您需要实时获取数据,可以使用“SnapshopListener”,否则只需使用“get()”调用。Firestore 默认启用离线持久性。因此,一旦您重新上线,您就可以从 Firebase 服务器获取所有更新。最好的解决方案?肯定是分页啦! (2认同)

小智 8

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

firestore.collection("yourCollection").get({source:"cache"})
Run Code Online (Sandbox Code Playgroud)