首页 > 解决方案 > Firebase子查询在删除一个键然后添加回来后出现零

问题描述

我运行下面的代码并使用数据库说孩子们的打印语句null

在此处输入图像描述

但是在数据库中肯定有一些东西:

在此处输入图像描述

我唯一能想到的是我让用户删除一条消息(通过删除-LoyeLv... 键),但如果他们想将其添加回来,他们可以。我保留了已删除密钥的副本,然后将其发送回数据库,以便消息仍然同步。唯一的问题是即使我不这样做(如在我的示例中)并且我删除了消息,回来并使用全新的密钥创建一个全新的消息,它仍然显示为空?

即使那里有孩子,这怎么可能?顺便说一句,这是我第一次遇到这种情况。

Database.database().reference()
            .child("favorite")
            .child(uid) // TKAETTLWAuREMZXCvrVeZd8yIPw2
            .queryOrderedByKey()
            .queryLimited(toLast: 10)
            .observeSingleEvent(of: .value, with: { [weak self](snapshot) in

                print(snapshot.key) // prints TKAETTLWAuREMZXCvrVeZd8yIPw2
                print(snapshot.value) // prints null

                if snapshot.hasChildren() {
                    print("yay")
                } else {
                    print("nay") // prints nay
                }

                // doesn't go past here
                guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }

更新我刚刚在下面尝试过,它工作正常,但上面仍然不起作用:

Database.database().reference()
            .child("favorite")
            .child(uid) // prints TKAETTLWAuREMZXCvrVeZd8yIPw2
            .observeSingleEvent(of: .value, with: { [weak self](snapshot) in

                print(snapshot.key) // prints TKAETTLWAuREMZXCvrVeZd8yIPw2
                print(snapshot.value) // prints the json data

                if snapshot.hasChildren() {
                    print("yay") // prints nay
                } else {
                    print("nay")
                }

我想删除该引用处的密钥而不是添加相同的密钥而不是再次删除它而不是添加一个全新的密钥会以某种方式抛出数据库?

再次更新而不是使用.queryOrderedByKey() 我将其更改为使用 .queryOrdered(byChild: "timeStamp") 并且它工作正常:

Database.database().reference()
            .child("favorite")
            .child(uid) // TKAETTLWAuREMZXCvrVeZd8yIPw2
            .queryOrdered(byChild: "timeStamp")
            .queryLimited(toLast: 10)
            .observeSingleEvent(of: .value, with: { [weak self](snapshot) in

当删除一个键然后将相同的确切键添加回数据库然后查询时queryOrderedByKey()必须导致某种内部问题,不仅会弄乱键,还会弄乱整个参考。我认为在我删除密钥之后会发生什么,无论内部跟踪机制将其从系统中擦除。当我把它加回来时,它不再是同一个键,而是一个String没有内部含义的常规,这就是为什么说null。我要求它查询一些没有意义的东西。这是一个疯狂的猜测。

但是我想知道为什么从未删除并重新添加到同一个引用的全新密钥会出现同样的问题?

这是@FrankvanPuffelen 在评论中要求的代码:

这是发送/删除数据的vc。

1- sendDataToFirebase()
2- deleteDataFromFirebase()
3- sendDataToFirebase()

按这个顺序做

var someOtherId = "12345" // this id has nothing to do with firebase and might be something like "x778-248-000"

var snapKey: String?
var originalTimeStamp: Double?

func sendDataToFirebase() {

    guard let uid = Auth.auth().currentUser?.uid else { return }
    guard let fbKey = Database.database().reference().child("favorite").childByAutoId().key else { return }

    let timeStamp = Date().timeIntervalSince1970

    var favoriteDict = [String: Any]()
    favoriteDict.updateValue(uid, forKey: "uid")
    favoriteDict.updateValue(originalTimeStamp ?? timeStamp, forKey: "timeStamp")

    var whichKeyToUse: String?

    if let snapKey = self.snapKey {

          whichKeyToUse = snapKey
    } else {

          whichKeyToUse = fbKey
    }  

    var carDict = [String: Any]()
    carDict.updateValue(originalTimeStamp ?? timeStamp, forKey: whichKeyToUse!)

    let favoriteRef = "favorite/\(uid)/\(whichKeyToUse!)"

    let carRef = "carType/\(someOtherId)/\(uid)"

    var multiLocationDict = [String: Any]()
    multiLocationDict.updateValue(favoriteDict, forKey: favoriteRef)
    multiLocationDict.updateValue(carDict, forKey: carRef)

    Database.database().reference().updateChildValues(multiLocationDict, withCompletionBlock: { (error, ref) in

           if self.snapKey == nil {

               self.snapKey = fbKey
           }

           if self.originalTimeStamp == nil {

               self.originalTimeStamp = timeStamp
           }

            // if no error this 100% saves it the way it's supposed to
    })
}

func deleteDataFromFirebase() {

    guard let uid = Auth.auth().currentUser?.uid else { return }
    guard let snapKey = self.snapKey else { return }

    let favoriteRef = "favorite/\(uid)/\(snapKey)"

    let carRef = "carType/\(someOtherId)/\(uid)"

    var multiLocationDict = [String: Any]()
    multiLocationDict.updateValue(NSNull(), forKey: favoriteRef)
    multiLocationDict.updateValue(NSNull(), forKey: carRef)

    Database.database().reference().updateChildValues(multiLocationDict, withCompletionBlock: { [weak self](error, ref) in

            // if no error this 100% deletes what it's supposed to
    })
}

2.这是读取数据的vc,这是一个完全不同的vc,问题出在哪里

func firstCheckIfCurrentUserExistsAtFavoriteRef() {

    guard let uid = Auth.auth().currentUser?.uid else { return }

    let favoriteRef = Database.database().reference()
        .child("favorite")
        .child(uid)
    favoriteRef.observeSingleEvent(of: .value) { [weak self](snapshot) in

        if !snapshot.exists() {
            return
        }

        print(snapshot.key) // prints the key
        print(snapshot.value) // *** the value prints fine here but in handlePagination it prints null ***

        if snapshot.hasChildren() {
            print("yay") // prints yay
        } else {
            print("nay")
        }

        self?.handlePagination(with: uid)
    }
}

var startKey: String?
func handlePagination(with currentUserId: String) {

    if startKey == nil {

        Database.database().reference()
            .child("favorite")
            .child(currentUserId)
            .queryOrderedByKey() // it works fine with this >>> .queryOrdered(byChild: "timeStamp")
            .queryLimited(toLast: 10)
            .observeSingleEvent(of: .value, with: { [weak self](snapshot) in

                print(snapshot.key) // prints the uid
                print(snapshot.value) // *** prints null but in firstCheckIfCurrentUserExistsAtFavoriteRef() it prints fine ***

                if snapshot.hasChildren() {
                    print("yay")
                } else {
                    print("nay") // prints nay
                }

                guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }

                // ...

            })

    } else {

        // it never makes it this far but it's the same code from above
        Database.database().reference()
            .child("favorite")
            .child(currentUserId)
            .queryOrderedByKey() // it works fine with this >>> .queryOrdered(byChild: "timeStamp")
            .queryEnding(atValue: startKey!)
            .queryLimited(toLast: 11)
            .observeSingleEvent(of: .value, with: { [weak self](snapshot) in

}

firstCheckIfCurrentUserExistsAtFavoriteRef()我打电话viewDidLoad

标签: iosswiftfirebasefirebase-realtime-databasesnapshot

解决方案


我之前在持久性打开的情况下看到过这个问题 - 问题是数据部分同步但不完全同步。

要进行快速测试,请尝试关闭持久性并重新运行查询。

Database.database().isPersistenceEnabled = false

这显然不是一个长期的解决方案,而只是为了测试。

如果要使用持久性,还需要确保数据保持最新并始终保持同步。这是代码

let postsRef = Database.database().reference(withPath: "posts")
postsRef.keepSynced(true)

Firebase 实时数据库客户端会自动下载这些位置的数据并保持同步,即使引用没有活动的侦听器也是如此。您可以使用以下代码行关闭同步

postsRef.keepSynced(false)

推荐阅读