【问题标题】:Realm syncing with large collection on Firestore - architectural questions / issues领域与 Firestore 上的大型集合同步 - 架构问题/问题
【发布时间】:2019-06-03 10:18:18
【问题描述】:

我在 Firestore 集合中有一组产品对象(标题、描述、价格、量化、urlString 等)。目前大约有 1000 个项目,但可能会达到 10k。在我的 iOS 应用启动时,我设置了一个集合侦听器 (db.collection("products").rx.listen()),然后将更改保存到本地 Realm 数据库。

.subscribe(onNext: { querySnapshot in
     querySnapshot.documentChanges.forEach { docChange in
                autoreleasepool {
                    let realm = try! Realm(configuration: Realm.Configuration.defaultConfiguration)
                    let newData = docChange.document.data()
                    if let item = itemFactory.createItem(using: newData) {
                        if (docChange.type == .added) {
                            //realm.add(item)
                        }
                        if (docChange.type == .modified) {
                            //realm.update(item)
                        }
                        if (docChange.type == .removed) {
                            //realm.delete(item)
                        }
                    }
                }
            }
        }, onError: { error in
            print("Error fetching snapshots: \(error)")
        }).disposed(by: disposeBag)

我已经详细阅读了 firestore 文档,但我不是 100% 确信这种方法是可靠的或高效的。

问题:当应用启动时,Firestore 会在描述更改之前每次下载所有 10k 文档吗?或者它会在第一次缓存所有 10k,然后仅在后续启动时下载更改。我确信一旦触发了更改事件,所有后续事件都只会获取对 Firestore 数据库的更改。我担心的是在应用程序启动时首先订阅侦听器,它会下载所有 10k 个项目(这将是昂贵的)。

2019 年 1 月 9 日编辑:

我最终实现了@zavtra 优雅的答案,代码大致如下:

var newestUpdatedAt = UserDefaults.standard.double(forKey: kUDItemUpdatedAt)
//...
db.collection(kProducts)
            .whereField(kUpdatedAt, isGreaterThan: newestUpdatedAt)
            .rx.listen()
//...

querySnapshot.documentChanges.forEach { docChange in
            autoreleasepool {
                let realm = try! Realm(configuration: Realm.Configuration.defaultConfiguration)
                let newData = docChange.document.data()
                if let item = itemFactory.createItem(using: newData) {
                    if item.updatedAt > newestUpdatedAt {
                       newestUpdatedAt = item.updatedAt
                    }
                    if (docChange.type == .added) {
                        //realm.add(item)
                    }
                    if (docChange.type == .modified) {
                        //realm.update(item)
                    }
                    if (docChange.type == .removed) {
                        //realm.delete(item)
                    }
                }
            }
        }
        UserDefaults.standard.set(newestUpdatedAt, forKey: kUDItemUpdatedAt)

【问题讨论】:

    标签: ios swift firebase realm google-cloud-firestore


    【解决方案1】:

    当应用启动时,Firestore 是否会在描述更改之前每次下载所有 10k 文档?

    当您使用 Firestore Query 的 addSnapshotListener() 方法在 Cloud Firestore 中侦听实时更改时,它:

    开始监听这个查询。

    这基本上意味着您第一次附加侦听器时,您将获得与该特定查询相对应的所有文档。

    或者它会在第一次缓存所有 10k,然后仅在后续启动时下载更改。

    因为 Firestore 默认启用了离线持久性,这意味着一旦您执行查询,结果就会在用户的设备上进行查询。此外,每次文档中的属性发生更改时,都会根据该更改通知您。显然,只有在侦听器保持活动且未被移除时才会发生这种情况。因此,如果数据库中没有任何更改,您将从缓存中获取全部数据。

    正如@zavtra 在他的回答中提到的那样,您可以在集合中的每个对象下添加一个 Date 属性(this 是您可以添加它的方式)并查询您的数据库客户端,根据这个新属性,用于自上次以来发生更改的所有文档。

    我还建议从post 中查看 Doug Stevenson 的回答,以便更好地理解。

    【讨论】:

    • 嗨,elprl!一切都好吗,我可以帮助您了解其他信息吗?
    • 我实现了@zavtra 答案,到目前为止似乎工作得很好。不必创建 Firestore 规则。我会用一些代码更新我的问题。
    • 感谢您的回答亚历克斯。我感兴趣地阅读了这些帖子。
    【解决方案2】:

    根据文档:

    docChanges 返回自上次以来文档更改的数组 快照。如果这是第一个快照,所有文档都将在 列为“添加”更改。

    每次重新启动应用程序时都会触发这种“第一次快照”行为。如果您想避免这种行为,您必须:

    1. 检索本地保存的最新文档及其时间戳。
    2. 构建一个查询,其中所有文档都从该时间戳开始(即每个文档的时间戳都至少是最近保存的时间戳)
    3. 订阅应用条目上该查询的更改。

    为此,您必须在每个文档中添加一个时间戳字段,并在时间戳字段的 Firestore 规则中添加一个“indexOn”规则,以防止客户端下载和排序整个集合。

    【讨论】:

    • 我可以假设您指的是该时间戳字段上的索引豁免吗?
    • 不,我的意思是创建一个索引。 firebase.google.com/docs/firestore/query-data/indexing 虽然 Firestore 应该自动管理索引,但我发现自己不得不手动添加一些 indexOn 规则。您可以跳过该过程并查看结果。如果需要创建索引,Firestore 将在您的 iOS 应用程序中创建一个日志,并提供一个链接供您访问以实现该规则。
    • 当新的侦听器正在查找某个日期的更改时,您如何知道何时删除了旧文档?除非你使用软删除。
    • 您必须在集合上添加一个字段,作为自上次访问后文档是否已被删除的标志,以及带有要在本地删除的文档 ID 数组的第二个字段。然后,一旦这些文档在本地被删除,您就可以更新标志。
    • 是的,我正在考虑一个软删除(isDeleted 字段),它可能具有删除那些每月安排的云功能的文档的逻辑。然后,一个月后仍未打开的任何应用都会从头开始重新同步。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多