0

In Firestore you can update fields in nested objects by a dot notation (https://firebase.google.com/docs/firestore/manage-data/add-data?authuser=0#update_fields_in_nested_objects). I wonder how to make that work in Typescript / Javascript.

For example the following object:

const user = {
    id: 1
    details: {
        name: 'Max',
        street: 'Examplestreet 38',
        email: {
            address: 'max@example.com',
            verified: true
        }
    },
    token: {
        custom: 'safghhattgaggsa',
        public: 'fsavvsadgga'
    }
}

How can I update this object with the following changes:

details.email.verified = false;
token.custom = 'kka';

I already found that Lodash has a set function:

_.set(user, 'details.email.verified', false);

Disadvantage: I have to do this for every change. Is their already a method to update the object with an object (like firestore did)?

const newUser = ANYFUNCTION(user, {
    'details.email.verified': false,
    'token.custom' = 'kka'
});

// OUTPUT for newUser would be
{
        id: 1
        details: {
            name: 'Max',
            street: 'Examplestreet 38',
            email: {
                address: 'max@example.com',
                verified: false
            }
        },
        token: {
            custom: 'kka',
            public: 'fsavvsadgga'
        }
    }

Does anyone know an good solution for this? I already found more solutions if I only want to change one field (Dynamically set property of nested object), but no solution for more than one field with one method

Paul
  • 2,430
  • 3
  • 15
  • 20

2 Answers2

1

I think you are stuck with using a function but you could write it yourself. No need for a lib:

function set(obj, path, value) {
    let parts = path.split(".");
    let last = parts.pop();
    let lastObj = parts.reduce((acc, cur) => acc[cur], obj);
    lastObj[last] = value;
}

set(user, 'details.email.verified', false);

if what you want to do is merge 2 objects then it is a bit trickier:

function forEach(target, fn) {
    const keys = Object.keys(target);
    let i = -1;
    while (++i < keys.length) {
        fn(target[keys[i]], keys[i]);
    }
}

function setValues(obj, src) {
    forEach(src, (value, key) => {
        if (value !== null && typeof (value) === "object") {
            setValues(obj[key], value);
        } else {
            obj[key] = value;
        }
    });
}

let obj1 = {foo: {bar: 1, boo: {zot: null}}};
let obj2 = {foo: {baz: 3, boo: {zot: 5}}};

setValues(obj1, obj2);

console.log(JSON.stringify(obj1));
JGoodgive
  • 1,068
  • 10
  • 20
  • 1
    After submitting my question I came up what a silly question I asked :D Thanks for your answer, yours is also a good one if someone not want to use lodash – Paul Sep 06 '18 at 18:27
0

One solution in combination with lodash _.set method could be:

function setObject(obj, paths) {
        for (const p of Object.keys(paths)) {
            obj = _.set(obj, p, paths[p]);
        }
        return obj;
}
Paul
  • 2,430
  • 3
  • 15
  • 20