Iterate through nested JSON tree and change values - javascript

What I have is a JSON tree of the following structure:
{
"projects": {
"Proj1": {
"milestones": {
"default": "20150101",
"default2": "20140406",
"default3": "20140101",
"default4": "20131231",
"default5": "20131220"
}
},
"Proj2": {
"milestones": {
"default": "20131231",
"default2": "20131220"
}
}
}
}
I have code to read it into a web page, with the 'default' part in text, and the numbers/dates in a text box/form. The idea is that you can change the dates and submit, which goes to the backend and gets written to a file. All that works for the most part. What I can figure out is how to iterate through the JSON tree I have and write the new values. For example:
Accessing JSONTREE.projects.Proj1.milestones.default returns the value for that key. Setting the value with that call changes the value appropriately. What I want to do is iterate through the entire tree and set the values of the 'defaults' based on whatever is in the form box. I have this:
$.each(formJSON.projects, function (projectName) {
$.each(this, function (selection) {
$.each(this, function (milestones, date) {
var saltKey = projectName + "-" + milestones;
date = document.getElementById(saltKey).value;
});
});
});
but it does nothing, even though 'alert(date)' returns a value. I suspect this is because it's the value, and not a reference to the object, but how can I get to the object? I suspect it's simple, but I'm not a pro with jQuery/JS.
TL;DR How do I get references to a key in a nested JSON tree so I can change the value?
EDIT: Okay, I think this is what I needed: JS/Jquery - using variable in json selector. I changed the 'date' portion to: formJSON.projects[projectName][selection][milestones] = document.getElementById(saltKey).value; which seems to work.

I ran into the same problem and this is my solution to iterate over a JSON object (MongoDB) and modify certain elements regardless of whether these are properties of the object or property is an array with more objects. I know the question is old, but it can be useful to someone.
Assuming we have an object like this or even more complex.
var mixData = {
"Hello": "World",
"Foo" : "Bar",
"sudo": [
{ "apt-get": "upgrade" , "force": false },
{ "apt-get": "update" , "force": true}
],
"colors": ["blue","green"],
"numbers":{
"integer": [
{"num": 1},
{"num": 2},
{"num": 3}
],
"operator": "addition"
}
};
And we want to replace some string (blue in this case), but we don't know where is or what kind of constructor has our data.
// Detect if the element is an Array
function isElementArray(element){
return (element.constructor === Array ? true : false);
}
//Detect if the element is an Object
function isElementObject(element){
return (element.constructor === Object ? true : false);
}
Now that we have these two functions, we use a third to iterate over the item, regardless of whether an object or array.
function iterate(element){
//Check if the element is an Object
if(isElementObject(element)){
for (var property in element){
if(isElementObject(element[property])){
element[property] = iterate(element[property]);
}else if(isElementArray(element[property])){
//An array
for(var x = 0; x < element[property].length; x++){
element[property][x] = iterate(element[property][x]);
}
}else{
if(element.hasOwnProperty(property)){
console.log("New object inside object property");
element[property] = iterate(element[property]);
}else{
element[property] = replaceElement(element[property].toString());
console.log("Single Element: " + element[property] )
console.log(element + " " + element[property]);
}
}
}
}else if(isElementArray(element)){
//An Array
for (var x = 0; x < element.length; x++){
element[x] = iterate(element[x]);
}
}else{
//Single element in array or property
element = replaceElement(element.toString());
console.log("Single Element : " + element);
}
return element;
}
And the function we need to use to replace our string.
function replaceElement(element){
if(element === "blue"){
return "Blue is the warmest color"
}else{
return element;
}
}
And finally, we can get the result:
console.log(iterate(mixData));
The result is:
{
"Hello": "World",
"Foo" : "Bar",
"sudo": [
{ "apt-get": "upgrade" , "force": false },
{ "apt-get": "update" , "force": true}
],
"colors": ["Blue is the warmest color","green"],
"numbers":{
"integer": [
{"num": 1},
{"num": 2},
{"num": 3}
],
"operator": "addition"
}
};
You can change the replace function to suit your needs. And of course, remove al the console logs.

Your editing the passed value and not the original JSON object.
One way to fix this is to create a new JSON object, build as you iterate through the existing one, and then overwrite the original or use the new JSON object.
Another is to create a var holding the original JSON object and either pass it through your functions or access it directly inside the functions.

Related

Navigating a nested javascript object dynamically using an array of indexes as a path [duplicate]

This question already has an answer here:
Index an array of arrays with an array of indexes in javascript
(1 answer)
Closed 2 years ago.
I have a Json file with an unknown depth of nested children, and i need to read that with javascript, and delete an element somewhere within the object. I have the path of the child to delete stored in an array called nestPath (example [0,0,3] where the path would be [0]->[0]->[3]). The problem is that i do not know how to dynamically target the object directly without using a variable to reference the Json object, but if i try to delete the variable it will only delete the reference, not the actual object within the Json.
I would like to dynamically access it with the path given by nestPath so that with an input of [0,1,2,3], i would be able to access: jsonObject[0][1][2][3] without using a variable, so that i can delete it.
The code i tried:
var nestPath = [0,0,1];
var stateObject = menuToolState['menu'];
for (var i = 0; i < nestPath.length; i++) {
if (i > 0) {
stateObject = stateObject['links'][nestPath[i]];
} else {
stateObject = stateObject[nestPath[i]];
}
}
delete stateObject;
menuToolState:
{
"menu": [
{
"name": "0",
"links": [
{
"name": "0-0",
"links": [
{
"name": "0-0-0",
"links": []
},
{
"name": "0-0-1 (delete this)",
"links": []
}
]
}
]
}
]
}
With this code i am able to access the information within the object, but i am not able to delete it as delete just deletes the reference. How can i achieve this?
Right, so to delete a property on an object you need to call delete on the direct holder of that property. E.g. if you want to delete a property ['nestedProp'] inside an object
{prop1: {prop2: {nestedProp: 'hello'}}}
you need to keep a reference to the actual object holding it. Which will be obj['prop1']['prop2'].
const someNestedObj = {
prop1: {
prop1_1: {nested1: 'hello'}
},
prop2: {
prop2_1: {nested1: 'world'}
}
};
function deleteProp(obj, propPath) {
let curObj = obj;
let parentObj = obj;
for (let prop of propPath) {
parentObj = curObj;
curObj = curObj && curObj[prop];
}
if (propPath[propPath.length - 1] in parentObj) {
delete parentObj[propPath[propPath.length - 1]];
} else {
throw new Error('No such property');
}
}
deleteProp(someNestedObj, ['prop1', 'prop1_1', 'nested1'])
console.log(someNestedObj);

Array cannot access elements?

I am playing with the amazon alexa skills and trying to write my own. I have an array for some elements of the skill, but I cannot access the elements. I believe I've done everything correctly and I've googled a fair bit, but nothing seems to be working?!
var myArray = [
{ "name" : "matt", "content" : "this is about matt" },
{ "name" : "james", "content" : "this is about james" },
];
I then have some code based on the user input which uses the name as a finder.
var requestedName = "matt";
var contentToRead = myArray.filter(function(v){ return v.name == requestedName; });
console.log("I'll read back, " + contentToRead.content);
The above console.log is coming back as undefined. I've tried to parse the results to an array, but nothing I try seems to work.
any ideas? I am sure it's something simple, but my knowledge isn't enough to actually know what specifically to look for to solve it!!
.filter filters the array, it removes values not matching the filter; what you'll get back is still an array with multiple objects (because the predicate may apply to more than one value in the array).
The behaviour you want, returning the first match, is implemented in .find:
var contentToRead = myArray.find(function (v) { return v.name == requestedName; });
Array.prototype.filter() creates a new array with all elements that pass the test implemented by the given function, so contentToRead is an array:
var myArray = [
{ "name" : "matt", "content" : "this is about matt" },
{ "name" : "james", "content" : "this is about james" },
];
var requestedName = "matt";
var contentToRead = myArray.filter(function(v) { return v.name === requestedName; });
// You can loop over contentToRead array
contentToRead.forEach(function(item) {
console.log("I'll read back, " + item.content);
});
filter creates a new array containing the elements for which the function you pass it returns true.
content isn't a property of the array, it is a property of each object inside that array.
You would need need to get elements out of the array to read their content.
contentToRead.forEach(function (currentValue) {
console.log("I'll read back, " + currentValue.content);
});
The value returned by myArray.filter(function(v){ return v.name == requestedName; });is an array containing the object matching your filter.
As you only have one object in it, you could access it like :
contentToRead[0].name

Get key values in JSON array

I'm trying to get the key values of each record in a JSON array when looping through it. Currently I have a simple JSON object like this:
"users": {
"key_11": {
"text": "11"
},
"key_22": {
"text": "22"
},
"key_33": {
"text": "33"
}
}
My current script uses the 'map' method to convert this JSON objet to a loop-able array:
var user_profiles_array = $.map(user_profiles_string, function(el) { return el; });
for (var xt = 0; xt < user_profiles_array.length; xt++) {
console.log(user_profiles_array[xt].text); //11 or 22
}
My question is, how can I get the value for e.g: 'key_11' or 'key_22'?
Thanks!
you can use Object.keys to get an array of all of your object's keys. Once you have that array, you can use Array.forEach to iterate over it as necessary:
Object.keys(usersObject).forEach(function(key, keyIndex) {
console.log("index:",keyIndex,"key:",key,"value:",usersObject[key]);
});
But!
your particular problem here is being caused by using $.map instead of JSON.parse. $.map returns an array, so of course your keys are always going to be numerical array indices - 0, 1, 2, and so on. You're not going to be able to use hash keys to find things in the array returned by $.map. Furthermore, judging by your variable names you're calling $.map on a string which is definitely not going to do what you want. Assuming you figure that part out and you somehow get a valid JavaScript object, and you still need to use $.map() for some reason, what you can do is this:
// $.map will return an array...
$.map(user_profiles_object, function(objVal, objKey) {
// ...and each item in that array will be an object with a
// property named 'key' and a property named 'val'
return {
key: objKey,
val: objVal
};
}).forEach(function(arrayObj) {
// now each item in the array created above will be an object
// created by your callback function:
console.log(arrayObj.key,":",arrayObj.val);
});
You can also rely on Js's foreach.
// JSON string must be valid. Enclose your JSON in '{}' (curly braces);
var user_profiles_string = '{ "users": { "key_11": { "text": "11" }, "key_22": { "text": "22" }, "key_33": { "text": "33" }}}';
var user_profiles_array = JSON.parse(user_profiles_string);
// For retrieval in loop, the Js foreach asigns the key to index param (i in this case).
for (i in user_profiles_array.users) {
// i is the key of the user currently iterated.
console.log('Key name is: ' + i);
// Use i as the index to retrieve array value.
console.log(user_profiles_array.users[i]);
}
// For direct retrieval using any given known key:
console.log(user_profiles_array.users['key_11']);

Converting array in to custom format

How can I convert the below array in to another format as specified below:
My array:
var test=[{"1":"Input"},{"2":"Output"}]
Converted array:
var result=
[
{
"id": "1",
"name": "Input"
},
{
"id": "2",
" name": "Output"
}
]
I tried with this code but not working.
var result = [];
for (var i = 0; i < test.length; i++) {
var newArray = {
id: Object.keys(test[i])[i],
name: test[i].name
}
result.push(newArray);
}
Inner array object doesn't have name property, so test[i].name will be undefined. You need to get the value using the key value. Also you can simplify your code using map() instead of for loop.
var test = [{
"1": "Input"
}, {
"2": "Output"
}];
var res = test.map(function(v) { // iterating over array object
var k = Object.keys(v)[0]; // getting object keys as an array & retrieving first key
return {
id: k, // setting id property as key
name: v[k] // and name property as value
}
});
document.write('<pre>' + JSON.stringify(res, null, 3) + '</pre>');
You should use array.prototype.map for converting an array to another array using a conversion function.
array.prototype.map will iterate on all items and run a "conversion function" on each item.
Since your item is a key-value that looks like this: {"1":"Input"}, the only problem you have is that you don't know the key.
To get the keys of each object you can use the Object.keys method.
var test=[{"1":"Input"},{"2":"Output"}]; // input
var newArr = test.map(function(item){
var key = Object.keys(item)[0]; // get the object's keys and take the only key.
return {id: key, name: item[key]} // return the new object
});

find a value inside array of JSON object [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I get below Array of JSON objects from JSP
"Titles":[
{
"Book3" : "BULLETIN 3"
}
,
{
"Book1" : "BULLETIN 1"
}
,
{
"Book2" : "BULLETIN 2"
}
]
On JS side, it is parsed and I see an array with 3 objects.
Now, I want to find/identify a value when I pass String key.
For e.g. when I pass "Book2" I should get value "BULLETIN 2".
Can someone help me identify the approach?
Try this
var data = {
"Titles": [{
"Book3": "BULLETIN 3"
}, {
"Book1": "BULLETIN 1"
}, {
"Book2": "BULLETIN 2"
}]
};
function getValueByKey(key, data) {
var i, len = data.length;
for (i = 0; i < len; i++) {
if (data[i] && data[i].hasOwnProperty(key)) {
return data[i][key];
}
}
return -1;
}
console.log(getValueByKey('Book2', data.Titles));
Having:
var x = [{
"Book3" : "BULLETIN 3"
}, {
"Book1" : "BULLETIN 1"
}, {
"Book2" : "BULLETIN 2"
}];
and
var key = "Book1";
You can get the value using:
x.filter(function(value) {
return value.hasOwnProperty(key); // Get only elements, which have such a key
}).shift()[key]; // Get actual value of first element with such a key
Notice that it'll throw an exception, if object doesn't have such a key defined.
Also, if there are more objects with such key, this returns the first one only. If you need to get all values from objects with such key, you can do:
x.filter(function(value) {
return value.hasOwnProperty(key); // Get only elements, which have such a key
}).map(function(value) {
return value[key]; // Extract the values only
});
This will give you an array containing the appropriate values only.
Additionally, if you're using jQuery, you can use grep instead of filter:
jQuery.grep(x, function(value) {
return value.hasOwnProperty(key);
}) /* and so on */;
To achieve this, you have to loop through the array elements's keys and test if the given key exists in the array, if so get its value:
var jsonTitles = [
{ "Book3" : "BULLETIN 3" },
{ "Book1" : "BULLETIN 1" },
{ "Book2" : "BULLETIN 2" }
]
function getValue(key, array) {
for (var el in array) {
if (array[el].hasOwnProperty(key)) {
return array[el][key];
}
}
}
alert(getValue("Book1", jsonTitles));
We use element[key] where element is array[el] to get the value of the given key.
Let's create a function to get an object in an array for that, that takes two arguments: the array and the key of the property you want to get:
function getObjectInArray(arr, key) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].hasOwnProperty(key)) return arr[i][key];
}
}
This loops through each object looking for that specific key.
Solution: Now you could do something like getObjectInArray(titlesJSONArray, "Book2") and it should return "BULLETIN 2".
var titlesJSONArray = [ { "Book3": "BULLETIN 3" }, ... ]; // and so on
var book2 = getObjectInArray(titlesJSONArray, "Book2"); // => "BULLETIN 2"
For such array/collection manipulation in Javascript I would suggest you to use underscorejs library. It provides functions that, to me, make everything much more simple. In your case:
function find_value(array, key) {
// find will run the provided function for every object in array
var obj_found = _.find(array, function(obj) {
// keys returns the keys inside an object
// so if the key of currently examined object
// is what we are looking for, return the obj
if (_.keys(obj)[0] === key) {
return obj;
}
});
// if an object with such key was found return its value
if (obj_found) {
return obj_found[key];
} else {
return null;
}
}
Here is a working fiddle of what I am suggesting.

Categories

Resources