Let's say, I have the following JSON, which can be easily converted back and forth to a JavaScript object:
{
"foo": {
"bar": "Common substitute word",
"baz": "Another mon substitute word",
"questionWords": {
"wat": "Inadequate question word",
"wut": "Even more inadequate question word"
}
}
}
And I receive modifications regarding this JSON in another JSON file, like this:
{
"foo.questionWords.wut": "A question word to avoid"
}
So the path to modify is given as a string. And I have to modify the first JSON by the new data.
But also the new data path possibly does not exist:
{
"foo.callingWords.dude": "Commonly used synonym for pal"
}
And the new data path might have indeterminable depth:
{
"who.knows.how.deep.we.will.go": "Look, a penny!"
}
What is the best way to handle this without a JS library, just by plain Vanilia JS?
(You can use the latest JavaScript features.)
Thank you for your help!
Let's say, I have the following JSON, which can be easily converted back and forth to a JavaScript object:
{
"foo": {
"bar": "Common substitute word",
"baz": "Another mon substitute word",
"questionWords": {
"wat": "Inadequate question word",
"wut": "Even more inadequate question word"
}
}
}
And I receive modifications regarding this JSON in another JSON file, like this:
{
"foo.questionWords.wut": "A question word to avoid"
}
So the path to modify is given as a string. And I have to modify the first JSON by the new data.
But also the new data path possibly does not exist:
{
"foo.callingWords.dude": "Commonly used synonym for pal"
}
And the new data path might have indeterminable depth:
{
"who.knows.how.deep.we.will.go": "Look, a penny!"
}
What is the best way to handle this without a JS library, just by plain Vanilia JS?
(You can use the latest JavaScript features.)
Thank you for your help!
Share Improve this question asked Feb 26, 2018 at 6:23 Erik KrániczErik Kránicz 4071 gold badge4 silver badges13 bronze badges 2- 1 Is there anything you've tried yet? What's worked? What outputs have you managed to get? – SCB Commented Feb 26, 2018 at 6:30
- Possible duplicate of Fastest way to flatten / un-flatten nested JSON objects – 0xtvarun Commented Feb 26, 2018 at 6:47
5 Answers
Reset to default 7Never use eval
for tasks like this. Split your "path" and walk step-by-step:
var data = {
"foo": {
"bar": "Common substitute word",
"baz": "Another mon substitute word",
"questionWords": {
"wat": "Inadequate question word",
"wut": "Even more inadequate question word"
}
}
},
mods = {
"foo.questionWords.wut": "A question word to avoid",
"foo.callingWords.dude": "Commonly used synonym for pal",
"who.knows.how.deep.we.will.go": "Look, a penny!"
};
function apply(data, mods) {
for (var path in mods) {
var k = data;
var steps = path.split('.');
var last = steps.pop();
steps.forEach(e => (k[e] = k[e] || {}) && (k = k[e]));
k[last] = mods[path];
}
return data
}
console.log(apply(data, mods))
One of the options in vanillaJS, you can use eval
(but be afraid, very afraid!)
like this:
var t = {
"foo": {
"bar": "Common substitute word",
"baz": "Another mon substitute word",
"questionWords": {
"wat": "Inadequate question word",
"wut": "Even more inadequate question word"
}
}
};
eval("t.foo.bar = 13")
Essentially the same as everybody's answer, just avoiding usage of eval(), if that could be a problem.
var obj={
"foo": {
"bar": "Common substitute word",
"baz": "Another mon substitute word",
"questionWords": {
"wat": "Inadequate question word",
"wut": "Even more inadequate question word"
}
}
}
var obj2={
"foo.questionWords.wut": "A question word to avoid"
}
for(var i in obj2){
var res = i.split(".");
var fieldName = res.splice(res.length-1,1);
var objField = res.reduce((r, u) => r && r[u] ? r[u] : '' , obj);
objField[fieldName]=obj2[i];
}
console.log(obj);
My solution using recursive function.
const modifyObject = (object, jsonPath, value) => {
const keys = jsonPath.split(".");
const key = keys.splice(0, 1);
if (keys.length > 0) {
modifyObject(object[key], keys.join('.'), value)
} else {
object[key] = value;
}
}
const obj = {
foo: {
bar: 11,
baz: 12,
bac: {
leng: 1,
str: 'hello world'
}
}
};
modifyObject(obj, 'foo.bac.leng', 'modified');
console.log(JSON.stringify(obj));
In imperative style where I'm just mutating source:
updateAll = function(source, target) {
Object.keys(target)
.forEach((k) => update(source, k, target[k]));
}
update = function(source, targetKey, targetValue) {
var keys = targetKey.split('.');
// Iterate as long as there are keys to shift out and as long as source is
// defined for that key.
while((key = keys.shift()) && source[key]) {
// If we're at a leaf, assign new value. Otherwise, iterate further into
// the object.
if (keys.length === 0 && typeof source[key] !== 'object') {
source[key] = targetValue;
} else {
source = source[key];
}
}
}