Eric
Eric

Reputation: 197

How to update multiple types of nodes in Firebase with one call (Swift)

I have a conversation node and inside are straightforward subnodes like displayMessage, conversationName, imageUrl etc, but there's also a messages node which holds additional subnodes describing all the messages sent inside the conversation w/ data like senderID, text, and timestamp. When the send message button is pressed, I'm trying to update the messages node with an additional message subnode and also the straightforward subnodes like displayMessage and lastMessageTime. However, the code I have completely replaces all nodes inside "messages" with just the new message node.

 fileprivate func sendMessage(uid: String, convoId: String) {


    let ref = Database.database().reference().child("conversations").child(convoId)

    let messageTime = NSDate().timeIntervalSince1970
    let messageInfo : [String:Any] = ["text":containerView.chatTextView.text, "senderId":uid, "timestamp": messageTime]
    let randomMessageId = NSUUID().uuidString
    let messageDict = [randomMessageId:messageInfo]

    let values = ["displayMessage":containerView.chatTextView.text, "lastMessageTime": messageTime, "messages":messageDict] as [String : Any]

    ref.updateChildValues(values) { (error, ref) in

        if error != nil {
            print (error as Any)
            return
        }

        self.containerView.clearChatTextField()

                }

}

Database Structure

Upvotes: 1

Views: 689

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

When you use updateChildValues, the Firebase server will loop over each key in the dictionary and call setValue on each key with the value you specified.

This means that it only merges on the top-level of the dictionary; on each child, it still replaces the existing values.

If you want to perform an update/append on lower levels of the JSON, you will need to encode the path to those children into the keys of the dictionary. So to add a new message to the messages child of the conversation, you will need to have the path for the new message as the key. You're already generating your own message ID, so all that is needed it so include it in the key instead of in the value of the dictionary:

let randomMessageId = NSUUID().uuidString

let values = ["displayMessage": containerView.chatTextView.text,
              "lastMessageTime": messageTime, 
              "messages/"+randomMessageId: messageInfo] as [String: Any]

Upvotes: 2

Related Questions