Firebase-for循环回调中嵌套的observeSingleEvent查询的更新时间过多

时间:2018-10-13 23:22:49

标签: ios swift firebase-realtime-database

我在Firebase实时数据库更新上面临严重的回调地狱。

情况: 我有一个comment节点,用于存储所有评论的详细信息,例如属于其userId(uid),message和post id(pid)的信息。请参见下图。

comments node data structure

我还有另一个评论后节点,该节点在每个帖子id项下存储评论项。请参见下图。

post-comment node data structure

最后,第三个节点是用户注释,它在唯一的用户帐户ID密钥下存储所有注释密钥。请参见下图。

user-comment node data structure

问题:

“写评论”功能一切正常,因为它只是创建评论键并将评论数据更新到这些节点。

但是,当用户调用“删除帖子”功能时,该功能将删除所有属于该帖子ID的评论数据。因此,我有这段代码逻辑性地循环所有注释数据。重点是,首先我必须获取评论后快照,以限制评论节点上的查询数量(因为评论节点存储了所有应用程序用户的评论详细信息数据。在不知道评论数量属于目标帖子的情况下,它将需要在注释节点上遍历for循环,这太重了。)

对于循环,注释后将获得commentKey,然后可以在注释节点和注释后节点上设置Null。

但是问题发生在我需要使用注释节点来找出userId的情况下,以便在用户注释上设置NSNull。当我致电以下活动时:

  

commentsRef.child((捕捉为AnyObject).key).observeSingleEvent(的:   .value,其中:{(commentSnapshot)in

     

})

commentsRef回调作用域成为另一个线程。因此,如果我在此作用域之外并且在for循环的末尾(注释后)调用rootRef.updateChildValues,它将仅更新注释节点和注释后节点。用户评论更新数据仍将在另一个线程上分配key:value。

  

updates [“ user-comment /(userId)/ comments /(commentKey)”] = NSNull()

我必须将rootRef.updateChildValue放入

  

commentsRef.child((捕捉为AnyObject).key).observeSingleEvent(的:   .value,其中:{(commentSnapshot)in

...

rootRef.updateChildValues(updates)
     

})

如果注释超过10,000或超过100万,则此逻辑将导致调用updateChildValues的次数过多,因为该注释在for循环中。我使用倒数方法尝试在for循环末端仅调用一次update。但是在commentRef范围内,计数始终为0 ...我不知道为什么...

请为我提供更好的解决方案,以解决此嵌套的watchSingleEvent更新问题,而无需更改当前节点的结构。我的目标是只调用rootRef.updateChildValue一次。

感谢您的帮助。

演示代码:

func deleteAllCommentsRelateTo(postId: String, callback: ((CommentServiceError?) -> Void)?) {
        var error: CommentServiceError?
        guard session.isValid else {
            error = .authenticationNotFound(message: "Authentication not found.")
            callback?(error)
            return
        }

        let uid = session.user.id
        let rootRef = Database.database().reference()
        let path1 = "posts/\(postId)/comments_count"
        let path2 = "posts/\(postId)/uid"

        let commentCountRef = rootRef.child(path1)
        let authorRef = rootRef.child(path2)

        authorRef.observeSingleEvent(of: .value, with: { authorSnapshot in
            guard let authorId = authorSnapshot.value as? String else {
                error = .failedToDelete(message: "Author not found")
                callback?(error)
                return
            }

            if uid != authorId {
                error = .failedToDelete(message: "User has no permission to delete this post comments")
                callback?(error)
                return
            }

            commentCountRef.runTransactionBlock({ (data) -> TransactionResult in

                if let _ = data.value as? Int {
                    data.value = 0
                }
                return TransactionResult.success(withValue: data)

            }) { (err, committed, snapshot) in
                guard err == nil, committed else {
                    error = .failedToDelete(message: "Unable to delete a comment")
                    callback?(error)
                    return
                }

                var updates: [AnyHashable: Any] = [:]

                    /**
                     * [CHECKED] Set NSNull() on comments, post-comment, and user-comment nodes.
                     */
                    let commentsRef = rootRef.child("comments")
                    let postCommentRef = rootRef.child("post-comment")
                    let query = postCommentRef.child(postId).child("comments").queryOrderedByKey()

                    query.observeSingleEvent(of: .value, with: { (data) in
                        guard data.hasChildren() else {
                            error = .failedToDelete(message: "No comments data")
                            callback?(error)
                            return
                        }

                        var count = data.childrenCount

                        print("post-comment count!!!!!!!: ", data.childrenCount)

                        for snap in data.children {
                            guard let commentKeySnap = snap as? DataSnapshot else {
                                continue
                            }

                            count -= 1

                            let commentKey = commentKeySnap.key

                            if count == 0 {
                                print("this is totally not right!!!!!")
                            }

                            updates["comments/\(commentKey)"] = NSNull()
                            updates["post-comment/\(postId)/comments/\(commentKey)"] = NSNull()

                            commentsRef.child((snap as AnyObject).key).observeSingleEvent(of: .value, with: { (commentSnapshot) in
                                guard let userId = commentSnapshot.childSnapshot(forPath: "uid").value as? String else {
                                    return
                                }


                                updates["user-comment/\(userId)/comments/\(commentKey)"] = NSNull()

                                print("In this observeSingleEvent will always be 0 count::::: ", count)

                                if count == 0 {
rootRef.updateChildValues(updates, withCompletionBlock: { err, ref in
                                            guard err == nil else {
                                                error = .failedToDelete(message: "Failed to delete comment")
                                                callback?(error)
                                                return
                                            }
                                        })

                                    print("deleteAllComments: ", updates)
                                    callback?(nil)
                                }
                            })
                            print("count down: ", count)
                        }
                    })
                })
            }
        })
    }

1 个答案:

答案 0 :(得分:0)

解决方案:

我不小心找到了放置count-= 1的正确位置。最初,我将其放置在for循环作用域中,但是该作用域中的commentRef并没有减少。因此,我将count-= 1放入commentRef范围中,该计数成功计数为零,并且仅调用rootRef.update一次。