Reputation: 96
I have nested JSON as below:
{
"fields": {
"type": "custom",
"level1": {
"type": "custom"
},
"level2": {
"type": "custom",
"level3": {
"type": "custom"
},
"level31": {
"type": "notcustom"
}
}
}
}
I want to extract all the values that have the key type
The output I would like is:
{
"fields":"custom",
"level1":"custom",
"level2":"custom"
}
Upvotes: 1
Views: 1515
Reputation: 18566
I tried to be simple using a recursive approach. At first checking whether it's an object or not. If its an object again call the function passing that object.
Else checking that key and appropriate value is there. Populating it in result object and returning it.
var object = {
"fields": {
"type": "custom",
"level1": {
"type": "custom"
},
"level2": {
"type": "custom",
"level3": {
"type": "custom"
},
"level31": {
"type": "notcustom"
}
}
}
};
function recursiveIterator(object, needle, value, result) {
var result = result || {};
for (var key in object) {
if (object[key][needle] === value) {
result[key] = object[key][needle];
}
if (typeof object[key] === "object") {
recursiveIterator(object[key], needle, value, result);
}
}
return result;
}
document.getElementById("result").textContent = JSON.stringify(recursiveIterator(object, "type", "custom"));
<div id="result"></div>
It's a very generic approach. You can pass key
such as type
in this case and what value you want to match, custom
in this case.
Upvotes: 2
Reputation: 64923
You need a recursive function to navigate the tree structure.
The following code snippet does it, and it adds the results to an array of custom fields.
I've not removed sub-properties of custom fields, so if a custom field had a sub-level property, the property is also included. You could remove these sub-properties but you would modify the source object tree too. Thus, this can be solved creating clones with Object.create
and removing the whole properties afterwards... but I believe that the whole code is enough to open your mind and understand how you would solve the issue.
Run the snippet to see the JSON result live!
Although you requested an object as a result (something like a dictionary after all), I suggest that array result should work better in this scenario, because if there's more than a "level" property called the same way (for example, two level1
properties), only the last one would be accessible in the result because it might be overwritten.
var obj = {
"fields": {
"type": "custom",
"level1": {
"type": "custom"
},
"level2": {
"type": "custom",
"level3": {
"type": "custom"
},
"level31": {
"type": "notcustom"
}
}
}
};
function getCustomFields(field, customFields) {
var customFields = typeof customFields != "undefined" ? customFields : [];
if (field["type"] == "custom") {
customFields.push(field);
}
// Object.keys gets all own object property names as an array
// in order to use filter to do a "where" the fieldName starts with
// "level" word. Once every "level" property is filtered, you execute
// an Array.forEach to execute the enclosing functin against the
// inner level giving each level field and current customFields array
// to accumulate results...
Object.keys(field).filter(function (fieldName) {
return fieldName.indexOf("level") == 0;
}).forEach(function (levelPropertyName) {
getCustomFields(field[levelPropertyName], customFields);
});
return customFields;
}
var customFields = getCustomFields(obj.fields);
document.getElementById("result").textContent = JSON.stringify(customFields);
<div id="result"></div>
Upvotes: 0