mystic cola
mystic cola

Reputation: 1643

Swift Retrieve Firebase Value from childByAutoID

I've read about a hundred posts on here about dealing with the value of "childByAutoId" children from Firebase's Realtime Database... but I haven't exactly found anything that would explain what I'm trying to do so I figured I'd finally break down and ask.

First off here's the database structure:

let database = Database.database().reference(withPath: "messages")
let db1 = database.child("sender").child("receiver").childByAutoId()

Pretty straightforward. I then wanted to retrieve the value of that autoID.

db1.observeSingleEvent(of: .value, with: { snapshot in
            guard let value = snapshot.value as? [String: Any] else{
                completion(.failure(DatabaseError.failedToFetch))
                print("GetAll Failed")
                return
            }

...returns the "failedToFetch" error, while:

database.child("sender").child("receiver").observeSingleEvent(of: .value, with: { snapshot in
            guard let value = snapshot.value as? [String: Any] else{
                completion(.failure(DatabaseError.failedToFetch))
                print("GetAll Failed")
                return
            }

...which is the same thing only excluding childByAutoId returns:

"-MrdAxlUKHvJWjtSQe7X": {
    body = "cookies";
    createdat = 1640294767943;
    msgId = "-MrdAxlUKHvJWjtSQe7X";
    name = glynis;
    receiverUid = LKJHdhkjhkjsh;
    senderUid = LAKSjksljlkajlk;
}

So now the data is coming in... but when I try to get the value of "-MrdAxlUKHvJWjtSQe7X" (the auto-generated key):

let things: [Thing] = value.compactMap({ dictionary in
                guard let name = value["name"] as? String,
                    let msgId = value["msgId"] as? String,
                    let body = value["body"] as? String,
                    let receiverUid = value["receiverUid"] as? String,
                    let senderUid = value["senderUid"] as? String,
                    let createdat = value["createdat"] as? String,
                    let dated = value["dated"] as? String,)else {
                            return nil
                    }

And I do a:

guard !things.isEmpty else {
                    print("thing are empty")
                    return
                }

They come up empty (even though "value" is certainly populated.) So my question is how would I properly retrieve the value of the generated key (childByAutoId)?

Upvotes: 0

Views: 90

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599776

Some of the problems I spot:

  1. Most of the fields in your value.compactMap( don't have a matching property in your snapshot just above it. E.g. createdat is not the same as value["created"], and there is no property tId in the snapshot.

  2. The types need to match up in order to make the as? String cast work. Your createdat value is a long number (probably the number of milliseconds since the epoch), so casting that to a string leads to nil. You should cast it to a long/number value, or convert by calling the String function, as shown here: Convert Int to String in Swift


Based on your edit...

This code:

database.child("sender").child("receiver").observeSingleEvent(of: .value, with: { snapshot in

Reads the entire sender/receiver node from your database, which contains one or more child nodes with auto-generated keys, and then properties under each of those child nodes.

When you do:

value = snapshot.value as? [String: Any]

This sets value to be a dictionary/map with the top-level key(s) being the childByAutoId. When you then access value["-MrdAxlUKHvJWjtSQe7X"] you get a map/dictionary with the properties of that child node.

You can also loop over the child nodes of the snapshot with something like:

for child in snapshot.children {
    let snap = child as! DataSnapshot //downcast

    let dict = snap.value as! [String: Any] // get properties of child node
    let msg = dict["body"] as! String
}

Upvotes: 0

Related Questions