Я столкнулся с серьезным адом обратного вызова при обновлении базы данных Firebase в реальном времени.
Ситуация: у меня есть узел комментариев, в котором хранится вся подробная информация о комментариях, например, принадлежат тому, чей userId (uid), сообщение и сообщениеid (pid).См. Изображение ниже.

У меня есть еще узлы пост-комментариев, в которых ключ комментариев хранится под каждым ключом идентификатора поста.См. Изображение ниже.

Наконец, третьи узлы - это комментарии пользователей, в которых все комментарии хранятся под уникальным ключом идентификатора учетной записи пользователя.Пожалуйста, см. Изображение ниже.

Проблема:
Все отлично работает с функцией «Написать комментарий», потому что она просто создает комментарийвведите и обновите данные комментариев к этим узлам.
Но, когда пользователь вызывает функцию «Удалить сообщение», которая удалит все данные комментариев, принадлежащие этому идентификатору записи.Поэтому у меня есть этот код, логически зацикливающий все данные комментариев.Все дело в том, что сначала я должен получить снимок пост-комментария, чтобы ограничить количество запросов на узле комментариев (поскольку узел комментариев хранит все подробные данные комментариев пользователя приложения. Не зная, сколько комментариев принадлежат целевой записи,он должен быть в цикле for по всему узлу комментариев, он слишком перегружен.)
Для цикла пост-комментария будет получен commentKey, тогда я могу установить значение Null для узла комментариев и пост-комментария.
Но проблемы случаются, мне нужно использовать узел комментариев, чтобы узнать идентификатор пользователя, чтобы установить NSNull для комментария пользователя.Когда я вызываю событие ниже:
commentsRef.child ((привязка как AnyObject) .key) .observeSingleEvent (of: .value, с: {(commentSnapshot) в
})
Область обратного вызова commentsRef становится другим потоком.Поэтому, если я вызову rootRef.updateChildValues за пределами этой области и в конце цикла for (post-comment), который будет обновлять только узел комментариев и узел post-comment.Данные обновлений пользовательского комментария будут по-прежнему назначать ключ: значение в другом потоке.
updates ["user-comment / (userId) / comments / (commentKey)"] = NSNull ()
Мне нужно поместить rootRef.updateChildValue в
commentsRef.child ((привязка как AnyObject) .key) .observeSingleEvent (of: .value, с: {(commentSnapshot) в
...
rootRef.updateChildValues(updates)
})
Эта логика приведет к тому, что updateChildValues будет вызываться слишком много раз, если комментарии превышают 10000 или более 1 миллиона, потому что они находятся взацикливание.Я использую метод обратного отсчета, пытаюсь вызвать update только один раз в конце цикла for.Но счетчик всегда равен 0 в области видимости commentRef ... Я не знаю, почему ...
Пожалуйста, помогите мне с лучшим решением для решения проблем с этим вложенным обновлением НаблюдатьSingleEvent без изменения текущих узловсостав.Моя цель - вызывать 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)
}
})
})
}
})
}