49

I have a data structure like:

enter image description here

I want to edit the value of "test" key in "first" object. I followed the document on https://firebase.google.com/docs/firestore/manage-data/add-data

But it did not work for me.

The nodejs code:

var setAda = dbFirestore.collection('users').doc('alovelace').update({
        first : {
            test: "12345"
            }
});

The result in firestore: enter image description here

The "test2" key was gone. However, I only want to update the value of "test" and keep the "test2".

Any solution for this problem?

0

9 Answers 9

69

According to the link you provided, it says this:

If your document contains nested objects, you can use "dot notation" to reference nested fields within the document when you call update():

Therefore you need to use dot notation to be able to update only one field without overwriting, so like this:

var setAda = dbFirestore.collection('users').doc('alovelace').update({
    "first.test": "12345"
});

then you will have:

 first
  test: "12345"
  test2: "abcd"
Sign up to request clarification or add additional context in comments.

5 Comments

It is not clear from the documentation that ther is a difference in behavior when using the second type signature of DocumentReference.update, which results in a hard write: firebase.google.com/docs/reference/js/…
If I wanted to delete the test.first entry of the test map, would I need to perform a get() operation, delete it manually and then update the whole first map? Or is there a similar operation to delete nested fields in maps? @peter
@ppicom you need to do something like this update({"first.test" :firebase.firestore.FieldValue.delete()});
This is not working with .set({...}, {merge: true) for some reason.
have u tried the one below stackoverflow.com/a/57217966/7015400 @rendom?
36

Peter's solution's great, but it's not works with dynamic key. Following code can works with it:

var nestedkey = 'test';
var setAda = dbFirestore.collection('users').doc('alovelace').update({
    [`first.${nestedkey}`]: "12345"
});

3 Comments

This is essentially the same as Peter's solution, except it uses template string...
Great thanks. I tried ${nestedKey} but it didnt worked until I cower it with [].
Tried to edit out the unnecessary "This code is far better" part and it erred with 'edit queue is full'
14

If you don't want an exception that occur if 'first' field doesn't exist, try using set with {merge: true} option instead of update.

var setAda = dbFirestore.collection('users').doc('alovelace').set({
        first : {
            test: "12345"
        }
}, {merge: true});

Edit:

Thanks to @Shane Walker, the latest version(9.8.1) of Firestore has been changed so that update works the same as set with {merge: true} option.

Firebase JavaScript SDK Release Notes

1 Comment

This method also works, but no exception is thrown if the field doesn't exist in the object, it's just added.
10

In case somebody is using TypeScript (like in Cloud functions for example) here is the code to update nested fields with dot notation.

var setAda = dbFirestore.collection('users').doc('alovelace').update({
    `first.${variableIfNedded}.test`: "12345"
});

3 Comments

@Vino make sure you are using TypeScript. What is exactly the code you are using?
When I attempt this approach like saveData[`picks.${matchId}.points`] = pickValue; where saveData is the Map that I end up writing into firebase. I get a new property created with the name "picks.94904.points" instead of writing into the map. I'm new to typescript so I'm assuming a syntax error. Any ideas why this happens?
@Chamanhm, you are over complicating your code. Try to make it simpler. Good luck
1

Try this one: Does it work like that?

var setAda = dbFirestore.collection('users').doc('alovelace').update({
        "first.test" : "12345"
});

Comments

1

For those who need something more generic and recursive, here is a function that updates a Foo Firestore document non destructively with a typescript Partial :

private objectToDotNotation(obj: Partial<Foo>, parent = [], keyValue = {}) {
    for (let key in obj) {
        let keyPath = [...parent, key];
        if (obj[key]!== null && typeof obj[key] === 'object')
            Object.assign(keyValue, this.objectToDotNotation(obj[key], keyPath, keyValue));
        else
            keyValue[keyPath.join('.')] = obj[key];
    }
    return keyValue;
}

public update(foo: Partial<Foo>) {
    dbFirestore.collection('foos').doc('fooId').update(
        this.objectToDotNotation(foo)
    )
}

Comments

1

Use the set function and passing merge: true in options to update deeply nested fields without overwriting other fields.

const firstore = firebase.firestore()
const ref = firestore.doc('users/alovelace').set({
  first : {
    test: "12345"
  }
}, { merge: true })

With this method, you can update a field even if it's buried 20 levels deep.

Comments

0

For Swift 4

let dictionary:[String:Any] = ["first.test" : "12345"]
let plansDocumentReference = Firestore.firestore().collection("users").document("alovelace")              
plansDocumentReference.updateData(dictionary) { err in
                if let err = err {
                    print("Error updating document: \(err)")

                }}

You can update multiple fields by adding records to the dictionary as well as build variable based sub-keys by replacing the fixed text in the dictionary with string variable.

This technique also works to replace entire single key sub-blocks in the document by using a dictionary as the value for any key

Comments

0

I was looking for a version in typescript without the extra params, having type completion in mind... Ended up with the following:

TS Playground example

function objectToDotNotation(obj: any): any {

    return Object.keys(obj).reduce( (dnObj, key) => {
        const value = obj[key];

        if (value !== null && typeof value === 'object') {            
            const childObj = objectToDotNotation(value);

            Object.keys(childObj).forEach( childKey => {
                dnObj = {...dnObj, [`${key}.${childKey}`]: childObj[childKey] };
            });
        } else {            
            dnObj = {...dnObj, [key]: value };
        }

        return dnObj;
    }, {});
}

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.