我在Firebase实时数据库更新上面临严重的回调地狱。
情况: 我有一个comment节点,用于存储所有评论的详细信息,例如属于其userId(uid),message和post id(pid)的信息。请参见下图。
我还有另一个评论后节点,该节点在每个帖子id项下存储评论项。请参见下图。
最后,第三个节点是用户注释,它在唯一的用户帐户ID密钥下存储所有注释密钥。请参见下图。
问题:
“写评论”功能一切正常,因为它只是创建评论键并将评论数据更新到这些节点。
但是,当用户调用“删除帖子”功能时,该功能将删除所有属于该帖子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)
}
})
})
}
})
}
答案 0 :(得分:0)
解决方案:
我不小心找到了放置count-= 1的正确位置。最初,我将其放置在for循环作用域中,但是该作用域中的commentRef并没有减少。因此,我将count-= 1放入commentRef范围中,该计数成功计数为零,并且仅调用rootRef.update一次。