21

From the Firebase note:

Given a single key path like alanisawesome, updateChildren() only updates data at the first child level, and any data passed in beyond the first child level is a treated as a setValue() operation. Multi-path behavior allows longer paths (like alanisawesome/nickname) to be used without overwriting data. This is why the first example differs from the second example.

I am trying to use a single function createOrUpdateData(object) in my code. In case of update, it updates first level children properly, but if I have nested object passed, then it deletes all other properties of that nested object.

Here's the code:

function saveUserDetails(email,object){
        var hashedEmail = Utilities.getHashCode(email);
        var userRef = ref.child(hashedEmail);
        return $q(function(resolve,reject){
            return userRef.update(object, function(error){
                if(error){
                    reject(error);
                }else{
                    resolve("Updated successfully!");
                }
            });
        });
    }

So if I pass:

{
   name: 'Rohan Dalvi', 
   externalLinks: { 
      website: 'mywebsite'
   }
}

Then it will delete other properties inside externalLinks object. Is there a cleaner and simpler way of avoiding this?

In short, how do I make sure nested objects are only updated and that data is not deleted.

1
  • Hi @DavidEast , thanks it works! Although I haven't tried to update an array inside a nested object. Commented Nov 20, 2015 at 3:04

3 Answers 3

30

You can use multi-path updates.

var userRef = ref.child(hashedEmail);
var updateObject = {
   name: 'Rohan Dalvi', 
   "externalLinks/website": 'mywebsite'
};
userRef.update(updateObject);

By using the "externalLinks/website" syntax in the object literal it will treat the nested path as an update and not a set for the nested object. This keeps nested data from being deleted.

Sign up to request clarification or add additional context in comments.

3 Comments

How can we do this with dynamic object names?
@OliverDixon With ES6 you can use computed property names, like this: js const dynamicProperty = 'foo'; const updateObject = { name: 'Rohan Dalvi', [dynamicProperty]: 'mywebsite' }; You can also combine a static string with a dynamic part like this: js const updateObject = { name: 'Rohan Dalvi', [`externalLinks/${dynamicProperty}`]: 'mywebsite' }; I hope that helps! Sorry for the formatting, I realized that stack overflow comments are not the best place to post code.
I get the following error using this method: FirebaseError: Function DocumentReference.update() called with invalid data. Invalid field path (externalLinks/website). Paths must not contain '~', '*', '/', '[', or ']' I update the following way: this.db.collection('members').doc(uid).update(changes);
19

This question provides a more recent solution that works with cloud firestore.

Rather than using "/", one may use "." instead:

var userRef = ref.child(hashedEmail);
var updateObject = {
   name: 'Rohan Dalvi', 
   "externalLinks.website": 'mywebsite'
};
userRef.update(updateObject);

Comments

0

To update nested object/map/dictionary in firebase database, you can use Firestore.Encoder to class/struct that is Codable.

Here is a Swift code example:

Models:

import FirebaseFirestore
import FirebaseFirestoreSwift

// UserDetails Model
class UserDetailsModel: Codable {
   let name: String, 
   externalLinks: ExternalLinkModel
}    

// UserDetails Model
class ExternalLinkModel: Codable {
   let website: String
}

Calling Firebase:

    import FirebaseFirestore
    import FirebaseFirestoreSwift

    let firestoreEncoder = Firestore.Encoder()

    let fields: [String: Any] = [
        // using firestore encoder to convert object to firebase map
        "externalLinks": try! firestoreEncoder.encode(externalLinkModel)
    ]

    db.collection(path)
        .document(userId)
        .updateData(fields, completion: { error in
             ...
    })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.