Firebase子查询在删除键然后再添加回键后显示为nil [英] Firebase child query coming up nil after deleting a key then adding it back

查看:61
本文介绍了Firebase子查询在删除键然后再添加回键后显示为nil的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行下面的代码,并使用打印语句,数据库表示子代为 null

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:

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

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

我会在那个引用上删除键,而不是添加相同的键,而不是再次删除它,而不是添加一个全新的键会导致db关闭.

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?

再次更新,而不是使用 .queryOrderedByKey(),我将其更改为使用.queryOrdered(byChild:"timeStamp"),并且运行良好:

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

删除键时,将相同的键添加回数据库中,然后通过 queryOrderedByKey()查询必须引起某种内部问题,这不仅会弄乱键,还会弄乱整个参考.我认为,删除密钥后,无论采用哪种内部跟踪机制,都会从系统中擦除密钥,这会发生什么.当我将其添加回去时,它不再是相同的键,而是只是一个没有内部含义的常规 String ,这就是为什么 null 的原因.我要它查询没有意义的东西.这是一个疯狂的猜测.

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?

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

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

这是发送/删除数据的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

}

我在 viewDidLoad

推荐答案

在启用持久性功能之前,我已经看到过此问题-问题是数据已部分同步但未完全同步.

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)

Firebase Realtime Database客户端自动下载数据在这些位置并保持同步,即使参考没有积极的听众.您可以使用下面的代码行

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)

这篇关于Firebase子查询在删除键然后再添加回键后显示为nil的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆