Reputation: 1072
Consider you have a complex deeply nested object with 15 - 20 levels and you want to query a certain node inside it based on a field and modify a particular attribute. How can we achieve it?
Following example is contrived and the object is not as complex as my case and not as deep so please don't suggest something like obj[phoneNumbers][0].number = somethingNew
I'm using a library called jsonpath in below example to query a specific node and get its value using jsonpath expression.
var jp = require("jsonpath");
const obj = {
firstName: "John",
lastName: "doe",
age: 26,
address: {
streetAddress: "naist street",
city: "Nara",
postalCode: "630-0192"
},
phoneNumbers: [
{
type: "iPhone",
number: "0123-4567-8888"
},
{
type: "home",
number: "0123-4567-8910"
}
]
};
const number = jp.query(obj, "$.phoneNumbers[0].number");
console.log(number);
// outputs: [ '0123-4567-8888' ]
Thank you.
Upvotes: 1
Views: 835
Reputation: 2181
Here is an answer using object-scan. The main advantage over lodash is that we can specify more generic path expressions and execute the command against multiple targets at the same time. This addition in functionality comes with added complexity, and hence which one to choose depends on your requirements.
// const objectScan = require('object-scan');
const object = { a: [{ b: { c: 3 } }] };
const get = (obj, needle) => objectScan([needle], {
abort: true,
rtn: 'value'
})(obj);
console.log(get(object, 'a[0].b.c'));
// => 3
console.log(get(object, '**.c'));
// => 3
console.log(get(object, 'a.b.c'));
// => undefined
const set = (obj, needle, val) => objectScan([needle], {
filterFn: ({ parent, property }) => {
parent[property] = val;
return true;
},
abort: true,
rtn: 'bool' // returns true iff executed
})(obj);
console.log(set(object, 'a[0].*.c', 4));
// => true
console.log(object);
// => { a: [ { b: { c: 4 } } ] }
console.log(set(object, 'x[0].y.z', 5));
// => false
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
Disclaimer: I'm the author of object-scan
Upvotes: 1
Reputation: 970
If you are okay with using lodash (npm i --save lodash) (https://lodash.com/) then its pretty easy to get or set the deeply nested value.
Get deeply nested value: (https://lodash.com/docs#get)
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// => 3
_.get(object, ['a', '0', 'b', 'c']);
// => 3
_.get(object, 'a.b.c', 'default');
// => 'default'
Set deeply nested value: (https://lodash.com/docs#set)
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4
_.set(object, ['x', '0', 'y', 'z'], 5);
console.log(object.x[0].y.z);
// => 5
Upvotes: 2