Firebase - вложенный запрос Наблюдать за одним вызовом для слишком большого времени обновления - PullRequest
0 голосов
/ 14 октября 2018

Я столкнулся с серьезным адом обратного вызова при обновлении базы данных Firebase в реальном времени.

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

comments node data structure

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

post-comment node data structure

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

user-comment node data structure

Проблема:

Все отлично работает с функцией «Написать комментарий», потому что она просто создает комментарийвведите и обновите данные комментариев к этим узлам.

Но, когда пользователь вызывает функцию «Удалить сообщение», которая удалит все данные комментариев, принадлежащие этому идентификатору записи.Поэтому у меня есть этот код, логически зацикливающий все данные комментариев.Все дело в том, что сначала я должен получить снимок пост-комментария, чтобы ограничить количество запросов на узле комментариев (поскольку узел комментариев хранит все подробные данные комментариев пользователя приложения. Не зная, сколько комментариев принадлежат целевой записи,он должен быть в цикле 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)
                        }
                    })
                })
            }
        })
    }

1 Ответ

0 голосов
/ 14 октября 2018

Решение:

Я случайно обнаружил правильное место для установки счетчика - = 1. Первоначально я поместил его в область видимости цикла for, но количество не уменьшилось в области видимости commentRef.Поэтому я помещаю count - = 1 в область видимости commentRef, успешное выполнение которого считается равным нулю, и вызываю rootRef.update только один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...