My JSON output is similar to this below object and we have an array values as showing below
const object1 = {
"sublists": {
"item": [{
"line": "1",
"amount": "1200.00",
"id": "227",
"item": "227",
"item_display": "5800520002800",
"quantity": "1"
}
],
"shipping": [{
"line": "1",
"amount": "1200.00",
"id": "227",
"quantity": "1"
}
]
}
}
I am trying to get the name of arrays and values in separate variable as showing below
Array name :item, line: , 1
Array name :item , amount : 1200
Array name :item, id : 227
and so on ...
the array properties can varry depending on the json ouput , im looking for a dynamic script in which i could access the array name and properties
Can someone help me on this ?
try this
function iterateObject(obj, parent) {
if (typeof obj == "object")
if (!Array.isArray(obj))
Object.keys(obj).forEach((prop) => {
if (typeof obj[prop] == "object") iterateObject(obj[prop], prop);
else console.log(`Parent name : ${parent}, ${prop} : ${obj[prop]}`);
});
else
obj.forEach((elem) => {
iterateObject(elem, parent);
});
else console.log(`Parent name : ${parent}, ${parent} : ${obj}`);
}
iterateObject(object1,"sublists");
UPDATE
this is code for your json in comment
iterateObject(object01,"item");
The easy way to achieve the desired outcome is to pass the 'parentKey' to the recursive call:
const object1 = {sublists: {sales_order: [], data: [{"key1": "a", "value": 2 }, {"key1": "b", "value": 4 }], memo: [{"key1": "a", "value": 5 }] } };
function printValues(obj, parentName = null) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
obj.forEach(o => console.log(`Array name: ${parentName}. Key1: ${o.key1}. Value: ${o.value}`));
} else {
for (let k in obj) {
printValues(obj[k], k);
}
}
};
printValues(object1) ;
The first if statement if to check if the varaible is an array or object. Logic taken from:
How do you check if a variable is an array in JavaScript?
Array name: data. Key1: a. Value: 2
Array name: data. Key1: b. Value: 4
Array name: memo. Key1: a. Value: 5
I believe this will solve your problem. I followed the recursive nature of the code you gave and adapted it to make sure it was giving the output you desired. If you have any questions please let me know, and I'll try to address them.
function printValues(obj) {
for (const [objKey, objValue] of Object.entries(
obj
)) {
if (
typeof objValue === 'object' &&
!objValue.length
) {
printValues(objValue);
} else if (
objValue !== undefined &&
objValue.length > 0
) {
for (let i = 0; i < objValue.length; i++) {
const currentObject = objValue[i];
let str = '';
for (const [key, value] of Object.entries(
currentObject
)) {
str += `Array name: ${objKey} , key1: ${key} , value: ${value}\n`;
}
console.log(str);
}
}
}
}
Related
I am trying to convert the keys in JSON to the capital case using Javascript. I am successful to some extent. However, it is not creating the arrays in the correct way. It is inserting numbers before every object inside an array.
Input:
{
"id": "123",
"retweetCheck": {
"result": "OK",
"checks": [
{
"cId": "123"
},
{
"cId": "456"
}
]
},
"tweetCheck": {
"result": "OK",
"cId": "345",
"check": "Fail"
}
}
Code to convert the keys to capital case:
var responseContent = context.getVariable("response.content") || "";
responseContent = JSON.parse(responseContent) || "";
transformedCapitalizedObj = keysToCapitalCase(responseContent);
var finalResponseObj = {
Data: transformedCapitalizedObj
};
context.setVariable("response.content", JSON.stringify(finalResponseObj));
The function
function objEntries(obj) {
const keys = Object.keys(obj);
const keyValuePairs = keys.map(key => {
const value = obj[key];
return [key, value];
});
return keyValuePairs;
}
function keysToCapitalCase(objToProcess) {
if (!objToProcess || typeof objToProcess !== "object") return null;
var finalObj = {};
objToProcess = objEntries(objToProcess);
objToProcess.forEach(function (entry) {
var key = entry[0];
var value = entry[1];
key = key.charAt(0).toUpperCase() + key.slice(1);
if (typeof value == "object" || (value instanceof Array)) {
value = keysToCapitalCase(value);
}
finalObj[key] = value;
});
return finalObj;
}
The output I am getting currently is:
{
"Data":{
"RetweetCheck":{
"Checks":{
"0":{
"CId":"123"
},
"1":{
"CId":"456"
}
},
"Result":"OK"
},
"Id":"123",
"TweetCheck":{
"CId":"345",
"Check":"Fail",
"Result":"OK"
}
}
}
But ideally, the output should look like this:
{
"Data": {
"Id": "123",
"RetweetCheck": {
"Result": "OK",
"Checks": [
{
"CId": "123"
},
{
"CId": "456"
}
]
},
"TweetCheck": {
"Result": "OK",
"CId": "345",
"Check": "Fail"
}
}
}
It is basically inserting a serial number before each object inside an array instead of []. How this can be rectified. Any help will really do wonders.
When you call your function keysToCapitalCase(), first check if you have an array (with ES6, you can do this using Array.isArray()), and if you do, you can map the objects / inner arrays within that array to the result of recursively calling your keysToCapitalize function. Otherwise, if you get a standard object that isn't an array, you can perform your standard object mapping:
const obj = { "id": "123", "retweetCheck": { "result": "OK", "checks": [{ "cId": "123" }, { "cId": "456" } ] }, "tweetCheck": { "result": "OK", "cId": "345", "check": "Fail" } };
function keysToCapitalCase(objToProcess) {
if (!objToProcess || typeof objToProcess !== "object") return null;
if(Array.isArray(objToProcess)) {
return objToProcess.map(obj => keysToCapitalCase(obj));
}
var finalObj = {};
objToProcess = Object.entries(objToProcess); // if you can support it, `Object.entries()` does what `objEntries` does
objToProcess.forEach(function(entry) {
var key = entry[0];
var value = entry[1];
key = key.charAt(0).toUpperCase() + key.slice(1);
if (typeof value == "object") {
value = keysToCapitalCase(value);
}
finalObj[key] = value;
});
return finalObj;
}
var finalResponseObj = {Data: keysToCapitalCase(obj)};
console.log(finalResponseObj);
I would probably write the above method in a similar way, but instead using some inbuilt functions to make it a little more concise, such as .map() and Object.fromEntries():
const obj = { "id": "123", "retweetCheck": { "result": "OK", "checks": [{ "cId": "123" }, { "cId": "456" } ] }, "tweetCheck": { "result": "OK", "cId": "345", "check": "Fail" } };
const cap = str => str.charAt(0).toUpperCase() + str.slice(1);
const keysToCapitalCase = (objToProcess) => {
if (Object(objToProcess) !== objToProcess) return null;
return Array.isArray(objToProcess)
? objToProcess.map(obj => keysToCapitalCase(obj))
: Object.fromEntries(Object.entries(objToProcess).map(([key, val]) => [
cap(key), Object(val) === val ? keysToCapitalCase(val) : val
]));
}
const finalResponseObj = {Data: keysToCapitalCase(obj)};
console.log(finalResponseObj);
As indicated by the {} brackets, instead of the wanted [] brackets you are creating an empty object and not an Array.
To create an Array just change your var finalObj = {}; to var finalObj = [];
with an Array finalObj[key] = value will no longer work, you will now have to use finalObj.push(value)
Base Object :
obj = {
"place": "{{base_gplaceId}}",
"feedInputs": [
{
"subCategoryQuestion": "{{base_gquestionId}}",
"context": "other",
"image": "abc.jpg",
"mediaMetadata": {
"stickerList": [
{
"id": "someid2",
"sticker": "delish",
"weight": 3
}
],
"textList": [
{
"text": "What an evening!!!"
}
]
}
}
]
};
more keys can have more nesting,
want to set the values of keys = "", one by one and push the updated object to an array
Expected OP :
[
{"place":"","feedInputs":[{"subCategoryQuestion":"{{base_gquestionId}}","context":"other","image":"abc.jpg","mediaMetadata":{"stickerList":[{"id":"someid2","sticker":"delish","weight":3}],"textList":[{"text":"Whatanevening!!!"}]}}]},
{"place":"{{base_gplaceId}}","feedInputs":[{"subCategoryQuestion":"","context":"other","image":"abc.jpg","mediaMetadata":{"stickerList":[{"id":"someid2","sticker":"delish","weight":3}],"textList":[{"text":"Whatanevening!!!"}]}}]},
{"place":"{{base_gplaceId}}","feedInputs":[{"subCategoryQuestion":"{{base_gquestionId}}","context":"","image":"abc.jpg","mediaMetadata":{"stickerList":[{"id":"someid2","sticker":"delish","weight":3}],"textList":[{"text":"Whatanevening!!!"}]}}]},
{"place":"{{base_gplaceId}}","feedInputs":[{"subCategoryQuestion":"{{base_gquestionId}}","context":"other","image":"","mediaMetadata":{"stickerList":[{"id":"someid2","sticker":"delish","weight":3}],"textList":[{"text":"Whatanevening!!!"}]}}]},
{"place":"{{base_gplaceId}}","feedInputs":[{"subCategoryQuestion":"{{base_gquestionId}}","context":"other","image":"abc.jpg","mediaMetadata":{"stickerList":[{"id":"","sticker":"delish","weight":3}],"textList":[{"text":"Whatanevening!!!"}]}}]}
,...........]
tried couple of recursions, but not able to break after update inside the nested objects,
any simplistic approach ?
You could iterate the properties and change the values who are not objects. For having access to the complete object store the root as well and take a copy of the object with stringify and parse for the result set.
function visitAll(object, root = object) {
return Object
.keys(object)
.flatMap(k => {
if (object[k] && typeof object[k] === 'object') return visitAll(object[k], root);
const value = object[k];
object[k] = '';
const result = JSON.parse(JSON.stringify(root));
object[k] = value;
return result;
});
}
var object = { place: "{{base_gplaceId}}", feedInputs: [{ subCategoryQuestion: "{{base_gquestionId}}", context: "other", image: "abc.jpg", mediaMetadata: { stickerList: [{ id: "someid2", sticker: "delish", weight: 3 }], textList: [{ text: "What an evening!!!" }] } }] },
result = visitAll(object);
result.forEach(o => console.log(JSON.stringify(o)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Have an object with following format:
let obj = {
p2: {
p21: [
{
key1: "val1",
value1: "val2"
},
{
prop: "test",
value: "dummy"
}
]
}
}
I basically have to see if there is an object that has key "prop" and replace with whatever the passed value. If such key does not present create an object with { "prop" : "test" , value: passed_value} and add it to the p21 array. Also this object containing key "prop" can be present anywhere inside p21 array
Should be something like this
function checkAndUpdate(replacingValue) {
if(obj's p21 has key name "prop")
{
//update its "value" to the passed "replacingValue"
}
else //if "prop" key not present
{
// create an object with { "prop": "test" , value: replacingValue} and add it to p21 array
}
}
Have tried following:
obj.p2.p21.map((elem) => {
if(Object.keys(elem)[0] === "prop")
elem.value = updateValue;
})
Use .findIndex to find the index of the matching object. If it exists, .slice the array before and after it, and in the middle, insert the updated object. Otherwise, just spread the object into the array:
let obj = {
"p2": {
"p21": [{
"key1": "val1",
"value1": "val2",
},
{
"prop": "test",
"value": "dummy"
}
]
}
}
function checkAndUpdate(value) {
const newObj = { prop: 'test', value}
const arr = obj.p2.p21;
const index = arr.findIndex(obj => obj.hasOwnProperty('prop'));
const newArr = index !== -1
? [...arr.slice(0, index), newObj, ...arr.slice(index + 1)]
: [...arr, newObj];
const fullNewObj = {
...obj,
p2: {
...obj.p2,
p21: newArr
}
};
return fullNewObj;
}
console.log(checkAndUpdate('foo'));
To also check whether the value is undefined, and remove the matching object from the array if so, just make the appropriate if checks, and slice the array as needed:
let obj = {
"p2": {
"p21": [{
"key1": "val1",
"value1": "val2",
},
{
"prop": "test",
"value": "dummy"
}
]
}
}
function checkAndUpdate(value) {
const newObj = { prop: 'test', value}
const arr = obj.p2.p21;
const index = arr.findIndex(obj => obj.hasOwnProperty('prop'));
const newArr = (() => {
if (index === -1) {
if (value === undefined) {
return arr;
}
return [...arr, newObj];
}
if (value === undefined) {
return [...arr.slice(0, index), ...arr.slice(index + 1)];
}
return [...arr.slice(0, index), newObj, ...arr.slice(index + 1)];
})();
const fullNewObj = {
...obj,
p2: {
...obj.p2,
p21: newArr
}
};
return fullNewObj;
}
console.log(checkAndUpdate('foo'));
You can use Array.find to find the object that hasOwnProperty prop and update
let obj = {
"p2": {
"p21": [{
"key1": "val1",
"value1": "val2",
},
{
"prop": "test",
"value": "dummy"
}
]
}
}
function rep(value) {
if (!value.length) {
obj.p2.p21 = [...obj.p2.p21].filter(e => e.hasOwnProperty('prop'));
return;
}
let ele = obj.p2.p21.find(e => e.hasOwnProperty('prop'));
if (ele) {
ele.value = value
return;
}
obj.p2.p21.push({
"prop": "test",
value
})
}
rep('test');
console.log(JSON.stringify(obj))
rep('');
console.log(JSON.stringify(obj))
Let's say I have nested objects, like:
var obj = {
"items":[
{
"name":"Item 1",
"value": "500",
"options": [{...},{...}]
},
{
"name":"Item 2",
"value": "300",
"options": [{...},{...}]
}
],
"name": "Category",
"options": [{...},{...}]
};
I want to remove the options property from any level deep from all the objects. Objects can be nested within objects, and arrays as well.
We're currently using Lodash in the project, but I'm curious about any solutions.
There is no straight forward way to achieve this, however you can use this below function to remove a key from JSON.
function filterObject(obj, key) {
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
filterObject(obj[i], key);
} else if (i == key) {
delete obj[key];
}
}
return obj;
}
and use it like
var newObject = filterObject(old_json, "option");
Modifying the above solution, To delete "dataID" which appears multiple times in my JSON . mentioned below code works fine.
var candidate = {
"__dataID__": "Y2FuZGlkYXRlOjkuOTI3NDE5MDExMDU0Mjc2",
"identity": {
"__dataID__": "aWRlbnRpdHk6NjRmcDR2cnhneGE3NGNoZA==",
"name": "Sumanth Suvarnas"
},
};
candidate = removeProp(candidate, "__dataID__")
console.log(JSON.stringify(candidate, undefined, 2));
function removeProp(obj, propToDelete) {
for (var property in obj) {
if (typeof obj[property] == "object") {
delete obj.property
let newJsonData= this.removeProp(obj[property], propToDelete);
obj[property]= newJsonData
} else {
if (property === propToDelete) {
delete obj[property];
}
}
}
return obj
}
A little modification of void's answer that allows for deletion of propertise which are also objects
function filterObject(obj, key) {
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (i == key) {
delete obj[key];
} else if (typeof obj[i] == 'object') {
filterObject(obj[i], key);
}
}
return obj;
}
We now use object-scan for data processing tasks like this. It's very powerful once you wrap your head around it. Here is how you'd answer your questions
// const objectScan = require('object-scan');
const prune = (input) => objectScan(['**.options'], {
rtn: 'count',
filterFn: ({ parent, property }) => {
delete parent[property];
}
})(input);
const obj = { items: [{ name: 'Item 1', value: '500', options: [{}, {}] }, { name: 'Item 2', value: '300', options: [{}, {}] }], name: 'Category', options: [{}, {}] };
console.log(prune(obj));
// => 3
console.log(obj);
// => { items: [ { name: 'Item 1', value: '500' }, { name: 'Item 2', value: '300' } ], name: 'Category' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
I had similar issues. So, I developed the following library. Please see the source code of the library on GitHub, and you can download it using npm.
You can use the function removePropertiesDeeply together with isInitialized as below to remove all non-initialized properties (such as an empty object, empty array, empty string, or non-finite number).
const {removePropertiesDeeply, isInitialized} = require("#thedolphinos/utility4js");
const object = {
a: null,
b: "",
x: {
a: null,
b: ""
},
y: [],
z: [
null,
"",
{a: null, b: ""},
[[{a: {b: null, c: ""}}]],
"abc"
]
};
removePropertiesDeeply(object, (x) => !isInitialized(x));
console.log(JSON.stringify(object)); // See that the object becomes {"z":["abc"]}.
I had a similar issue and I got it resolved. I hope my solution might be helpful to someone.
I use Es6 ... spread operator to do a shallow copy of an object and made null to property I was not interested.
const newObject = {
...obj.items,
...obj.name,
options: null // option property will be null.
}
function omit(source) {
return isArray(source)
? source.map(omit)
: isObject(source)
? (({ options, ...rst }) => mapValues(rst, omit))(source)
: source;
}
as with lodash, that's an easy thing, also you can specify the key via an param like this
function omit(source, omitKey) {
return isArray(source)
? source.map(partialRight(omit,omitKey)))
: isObject(source)
? (({[omitKey]: _, ...rst }) => mapValues(rst, partialRight(omit,omitKey)))(source)
: source;
}
You can remove properties given a condition using following function:
// Warning: this function mutates original object
const removeProperties = (obj, condition = (key, value) => false) => {
for (var key in obj) {
const value = obj[key]
if (!obj.hasOwnProperty(key)) continue
if (typeof obj[key] === "object") {
removeProperties(obj[key], condition)
} else if (condition(key, value)) {
delete obj[key]
}
}
return obj
}
Examples:
// Remove all properties where key is equal to 'options'
removeProperties(someObject, (key, value) => key === 'options'))
// Remove all properties where key starts with 'ignore_'
removeProperties(someObject, (key, value) => key.startsWith('ignore_'))
// Remove all properties where value is null
removeProperties(someObject, (key, value) => value === null))
I am trying to convert a JSON string in a Javascript object literal. I think it is possible with some loops, but i couldn't get it done. The target structure is shown below, "chartData".
Fiddle can be found here: http://jsbin.com/ajemih/13/edit
Here's the JSON data:
{
"1b":{
"allLoad":"130",
"loadMovement":"111",
"allMovement":"111"
},
"1a":{
"allLoad":"910",
"loadMovement":"671",
"allMovement":"280"
},
"systemLoad":"963"
}
This should it look like after the conversion:
chartData = [[['loadMovement', 111],
['allMovement', 120],
['allLoad', 130]],
[['Load+Move', 671],
['allMovement', 280],
['allLoad', 910]]];
I think this would work:
Working demo: http://jsfiddle.net/jfriend00/YmjDR/
var data = {
"1b":{
"allLoad":"130",
"loadMovement":"111",
"allMovement":"111"
},
"1a":{
"allLoad":"910",
"loadMovement":"671",
"allMovement":"280"
},
"systemLoad":"963"
};
var chartData = [];
for (var i in data) {
var item = data[i];
var outer = [];
// skip over items in the outer object that aren't nested objects themselves
if (typeof item === "object") {
for (var j in item) {
var temp = [];
temp.push(j);
temp.push(item[j]);
outer.push(temp);
}
}
if (outer.length) {
chartData.push(outer);
}
}
You could do something like this:
var chartData = []
for(var key in data) {
var properties = data[key];
if(typeof properties === "object") {
var array = [];
for(var propKey in properties) {
array.push([propKey, properties[propKey]])
}
chartData.push(array);
}
}
Check out the fiddle.
You need to map the data manually. Thats actually more a diligent but routine piece of work.
var jsonData = 'your json string';
Object.keys( jsonData ).map(function( key ) {
if( typeof jsonData[ key ] === 'object' ) {
return Object.keys( jsonData[ key ] ).sort(function( a, b ) {
return +jsonData[ key ][ a ] - +jsonData[ key ][ b ];
}).map(function( name ) {
return [ name, jsonData[ key ][ name ] ];
});
}
}).filter( Boolean );
The above code will sort each group by its numeric value and then map a new array in the required style. Since .map() possibly returns undefined values on non-object elements, we need to filter those out before or afterwards.
See http://jsfiddle.net/WjZB2/2/
I had similar problem.
My goal was to convert a list of strings into a valid format for http://ivantage.github.io/angular-ivh-treeview/
This was my starting point:
[
"A\\A1\\Test1",
"A\\A1\\Test2",
"A\\A2\\Test3",
"B\\Test4",
"B\\Test5",
"B\\B1\\Test6",
"B\\B1\\Test7",
"B\\B1\\Test8",
"C\\C1\\C1a\\Test9",
"C\\C1\\C1b\\Test10",
"C\\C2\\C2a\\Test11",
"C\\C2\\C2a\\Test12",
"C\\C2\\C2a\\Test13",
"C\\C3\\Test14",
"C\\Test15",
"C\\Test16"
]
And I needed following format:
[
{
"label": "Selected Tests",
"children": [
{
"label": "A",
"children": [
{
"label": "A1",
"children": [
{
"label": "Test1",
"value": true
},
{
"label": "Test2",
"value": true
}
]
},
{
"label": "A2",
"children": [
{
"label": "Test3",
"value": true
}
]
}
]
}
]
}
]
See my solution https://jsfiddle.net/ydt3gewn/