首页 > 解决方案 > Firestore 在快照中查询快照?

问题描述

每当有人回复用户评论过的帖子时,我都会尝试收听任何通知。下面是我的数据库结构的外观。

目前我的代码有 2 个快照监听器。第一个监听 Posts 集合,其中用户位于“回复”数组中。然后第二个监听 Replies 集合,它返回所有添加了 != 当前用户的文档。当检测到新回复时,它将设置标签栏项目的标记。

这目前有效,但我很好奇是否有更好的方法。

func getNotifications() {
        database.collection("Posts")
            .whereField("replies", arrayContains: userData["userId"]!)
            .order(by: "timestamp", descending: true)
            .limit(to: 70)
            .addSnapshotListener() { (querySnapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err)")
                }
                else {
                    guard let snapshot = querySnapshot else {
                        print("Error fetching snapshots: \(err!)")
                        return
                    }
                    snapshot.documentChanges.forEach { documentd in
                        if (documentd.type == .added) {
                            let dataTemp = documentd.document.data()
                            let ifUser = dataTemp["ownerId"] as! String

                            if(ifUser == self.userData["userId"]!) {
                                database.collection("Posts")
                                    .document(documentd.document.documentID)
                                    .collection("Replies")
                                    .whereField("timestamp", isGreaterThan: dataTemp["timestamp"] as! Int)
                                    .addSnapshotListener() { (querySnapshot3, err) in
                                        if let err = err {
                                            print("Error getting documents: \(err)")
                                        }
                                        else {
                                            guard let snapshot = querySnapshot3 else {
                                                print("Error fetching snapshots: \(err!)")
                                                return
                                            }
                                            snapshot.documentChanges.forEach { diff in
                                                if (diff.type == .added) {
                                                    let temp = diff.document.data()
                                                    if((temp["ownerId"] as! String) != self.userData["userId"]!) {
                                                        print("new reply")
                                                        newArr.append(diff.document.data())
                                                        let data = diff.document.data()
                                                        let firebaseTime = data["timestamp"] as! Int
                                                        let date = lround(Date().timeIntervalSince1970)
                                                        if(firebaseTime+10 > date) {
                                                            self.tabBar.items![2].badgeValue = "●"
                                                            self.tabBar.items![2].badgeColor = .clear
                                                            self.tabBar.items![2].setBadgeTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], for:.normal)
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                            }
                            else {
                                database.collection("Posts")
                                    .document(documentd.document.documentID)
                                    .collection("Replies")
                                    .whereField("ownerId", isEqualTo: self.userData["userId"]!)
                                    .order(by: "timestamp", descending: false)
                                    .limit(to: 1)
                                    .getDocuments() { (querySnapshot2, err) in
                                        if let err = err {
                                            print("Error getting documents: \(err)")
                                        }
                                        else {
                                        var timestamp = Int()
                                        for documentde in querySnapshot2!.documents {
                                                 
                                            let temp = documentde.data()
                                            timestamp = temp["timestamp"] as! Int
                                        
                                            
                                            database.collection("Posts")
                                                .document(documentd.document.documentID)
                                                .collection("Replies")
                                                .whereField("timestamp", isGreaterThan: timestamp)
                                                .addSnapshotListener() { (querySnapshot3, err) in
                                                    if let err = err {
                                                        print("Error getting documents: \(err)")
                                                    }
                                                    else {
                                                        guard let snapshot = querySnapshot3 else {
                                                            print("Error fetching snapshots: \(err!)")
                                                            return
                                                        }
                                                        snapshot.documentChanges.forEach { diff in
                                                            if (diff.type == .added) {
                                                                let temp = diff.document.data()
                                                                if((temp["ownerId"] as! String) != self.userData["userId"]!) {
                                                                    print("new reply")
                                                                    newArr.append(diff.document.data())
                                                                    let data = diff.document.data()
                                                                    let firebaseTime = data["timestamp"] as! Int
                                                                    let date = lround(Date().timeIntervalSince1970)
                                                                    if(firebaseTime+10 > date) {
                                                                        self.tabBar.items![2].badgeValue = "●"
                                                                        self.tabBar.items![2].badgeColor = .clear
                                                                        self.tabBar.items![2].setBadgeTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], for:.normal)
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

    }

标签: swiftfirebasegoogle-cloud-firestore

解决方案


您的代码不仅有两个侦听器,而且您感兴趣的用户曾经回复过的每个帖子都有一个侦听器。这将很快导致糟糕的性能,并且可能会使您的应用程序崩溃,因为 Firestore 限制每个客户端 100 个侦听器。

我建议重新设计您的数据模型:

  1. 用户曾经回复过的帖子只有一个听众(您的第一个听众)
  2. 在每个回复增加一个回复计数器在 post doc 中,这将触发上面的快照。
  3. 优化 1:在帖子的每个操作上,您可以设置一个字段,该字段仅对回复lastactiontype具有特定值。reply这样,快照仅在回复时触发。
  4. 优化 2:将timestamp每个动作的字段设置为当前时间,并且只拉取快照中的最后 n 个(例如 10 个)帖子,这将限制加载时的读取次数。当您的应用程序离线并重新在线并且快照的所有 n 个帖子都已更改时,您将必须实现一些特殊的逻辑来处理这种情况。如果您的应用程序要扩展,这是必须的(您不想要一个对包含 100k 文档的集合没有限制的快照......)

例子:

firestore.collection("Posts")
.where( "lastaction", "==" , "reply")
.where( "replies", "array-contains", uid)
.orderBy("timestamp", "desc").limit(10)

推荐阅读