Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there a recommended way to use JSON Path to set a value? #126

Closed
devarda opened this issue Jun 23, 2020 · 1 comment
Closed

Is there a recommended way to use JSON Path to set a value? #126

devarda opened this issue Jun 23, 2020 · 1 comment
Labels

Comments

@devarda
Copy link

devarda commented Jun 23, 2020

I've had to implement my own reverse logic for a simple case like the following example. Are there any recommended approaches to set via JSON Path?

// say that I have a person object and,
// I want to make sure there will always be name fields, etc.
let given_person = {
    'age'             : 30,
    'email'           : 'abc@example.com',
    // let's add first_name, last_name fields
    'something_deeper': {
        'abc': 1,
        // let's add quantity here
    },
};

// defined an object with "json_path":"value" format,
// made sure it is not a deep object.
let obj1 = {
    '$.first_name'               : 'John',
    '$.last_name'                : 'Doe',
    '$.something_deeper.quantity': 11,
};

// since the above object is not deep, 
// I iterated over and found the field without using this library to set,
// used it for making sure we are overwriting if the value does not exist
// made it handle only simple paths like those above

for (let [k, v] of Object.entries(obj1)) {
    if (JSONPath({path: k, json: given_person, wrap: false}) === undefined) {
        let keys = k.split('.');
        if (keys[0] === '$') keys.shift();
        //we are left with something like ["first_name"] or ["something_deeper", "quantity"]

        // here set using a function that basically does obj[k1][k2][k3] = value
        setDeep(keys, v, given_person);

    }

}

//given_person would now look like
/*
{
    'age' : 30,
    'email' : 'abc@example.com',
    'first_name' : 'John',
    'last_name'  : 'Doe',
    'something_deeper': {
        'abc'   : 1,
        'quantity': 11,
    },
}
*/
@brettz9
Copy link
Collaborator

brettz9 commented Jun 28, 2020

There is no ability to specify a full jsonpath for setting (though see #124 in case this may be a candidate for standardization).

However, if you can adapt your object of paths to move the final key and value into its own object, you can indicate arbitrary json paths leading up to the key:

          it.only('Setting', function () {
            const expected = {
                age: 30,
                email: 'abc@example.com',
                'something_deeper': {
                    abc: 1,
                    quantity: 11
                },
                first_name: 'John',
                last_name: 'Doe'
            };
            const givenPerson = {
                age: 30,
                email: 'abc@example.com',
                // let's add first_name, last_name fields
                'something_deeper': {
                    abc: 1
                    // let's add quantity here
                }
            };

            // A two-level object of arbitrary JSON paths (minus the final key to modify) mapped to the key-values to modify
            const obj1 = {
                $: {
                    'first_name': 'John',
                    'last_name': 'Doe'
                },
                '$.something_deeper': {
                    quantity: 11
                }
            };

            Object.entries(obj1).forEach(([path, valuesToSet]) => {
                jsonpath({
                    json: givenPerson,
                    path,
                    wrap: false,
                    callback (obj) {
                        Object.entries(valuesToSet).forEach(([key, val]) => {
                            obj[key] = val;
                        });
                    }
                });
            });
            const result = givenPerson;
            assert.deepEqual(result, expected);
        });

Closing as I think this should address, though feel free to comment further as needed.

@brettz9 brettz9 closed this as completed Jun 28, 2020
brettz9 added a commit to brettz9/JSONPath that referenced this issue Jun 28, 2020
- Docs: Link to XPath 2.0 tester
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants