Firebase child query coming up nil after deleting a key then adding it back

折月煮酒 提交于 2020-06-18 02:37:26

问题


I run the code below and using print statements the Database is saying the children are null

But in the Database there is definitely something there:

The only thing I can think of is I let a user delete a message (by deleting the -LoyeLv... key) but if they want to add it back they can. I keep a copy of the deleted key and just send it back to the database so that the message in still in sync. The only problem with that is even when I don't do it (as in my example) and I delete the message, come back and make a completely new one with a completely new key, it's still coming up as null?

How is this possible even though there are children there? Btw this is the first time this has ever happened to me.

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 }

Update I just tried this below and it works fine but the above still doesn't work:

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")
                }

I woder does deleting the key at that ref than adding the same key than deleting it again than adding a brand new key somehow throws the db off?

Update Again Instead of using .queryOrderedByKey() I changed it to use .queryOrdered(byChild: "timeStamp") and it works fine:

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

When deleting a key then adding the same exact key back to the db then querying by queryOrderedByKey() must cause some sort of internal problem that doesn't just mess up the key, it messes up the entire ref. I think what happens is after I delete the key, whatever internal tracking mechanism wipes it from the system. When I add it back it's no longer the same key but instead just a regular String with no internal meaning and that's why is says null. I'm asking it to query something with no meaning. This is a wild guess.

But I would like to know why the same problem occurs with brand new keys that have never been deleted and added back at that same ref?

Here's the code that @FrankvanPuffelen requested in the comments:

This is the vc that sends/deletes the data.

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

Do it in that order

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. This is the vc that reads the data, this is an entirely different vc and where the problem lies

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

}

I call firstCheckIfCurrentUserExistsAtFavoriteRef() in viewDidLoad


回答1:


I have seen this issue before with persistence turned on - the issue is the data is partially sync'd but not fully.

For a quick test, try turning persistence off and re-running the query.

Database.database().isPersistenceEnabled = false

That's obviously not a long term solution but just for testing.

If you want to use persistence, you also need to ensure the data is kept fresh and always in sync. Here's the code

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

The Firebase Realtime Database client automatically downloads the data at these locations and keeps it in sync even if the reference has no active listeners. You can turn synchronization back off with the following line of code

postsRef.keepSynced(false)


来源:https://stackoverflow.com/questions/57972133/firebase-child-query-coming-up-nil-after-deleting-a-key-then-adding-it-back

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!