Renaming object keys which are nested - javascript

I am accessing JSON which looks like this.
[
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
...
}
}, ...
And I am having trouble renaming the object keys which have the . in the name to an _. For example:
item.Type or selection.Type to item_Type or selection_Type.
This is what I am trying to use:
var json = jsonFromExampleAbove;
str = JSON.stringify(json);
str = str.selectionFile.replace(/\".\":/g, "\"_\":");
json = JSON.parse(str);
console.log(json);
I am getting a console log error. I think it is because the values I am trying to replace are nested, but not sure. I am still very much a beginner here.
Thank you.

I would be tempted to do it with a bit of recursion using Object.entries and Object.fromEntries
const input = [
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
}
}];
function replaceDots(obj){
return Object.fromEntries(Object.entries(obj).map( ([key,value]) => {
const newKey = key.replace(".","_");
return typeof value == "object"
? [newKey, replaceDots(value)]
: [newKey, value]
}));
}
const result = input.map(replaceDots);
console.log(result);

Your solution with a replaceAll on the stringified JSON could result in unwanted problems when a value contains a dot.
For renaming nested keys of an object you need go over the object recursively and assign the new keys while removing the old ones
// for ES6
function renameKey(obj) {
// loop over all keys
for (let k in obj) {
// apply recursively if value is an object
if (typeof obj[k] === "object" && obj[k] !== null)
renameKey(obj[k]);
// only replace keys of type String
if (typeof k === 'string' || k instanceof String) {
const newKey = k.replaceAll(".", "_");
// assign {newKey:value} to object and delete old key
delete Object.assign(obj, { [newKey]: obj[k] })[k];
}
}
return obj
}

You can use a recursive approach to replace the keys in the input object(s) with your desired result. There's no need to use JSON.stringify(), one can simply iterate through the objects.
We'll use searchValue to specify what we wish to search for and newvalue to specify the replacement, in this case they will be /./g and '_'.
let arr = [
{
"itemType": "SelectionTitle",
"_id": "5ada2217c114ca048e1db9b0",
"created_by": "5ab57289d8d00507b29a3fdd",
"selectionFile": {
"item.Type": "SelectionFile",
"name": "1105F.MID",
"active": true,
"isFactory.Default": false,
"selection.Type": "Music",
"sfzFile": "",
"destination": "/data/uploads",
"encoding": "7bit",
"fieldname": "file",
"filename": "782f49a7cd72b865b4e2d286816792e7"
}
}
]
function replaceKeys(obj, searchvalue, newvalue, newObj) {
if (!newObj) newObj = Array.isArray(obj) ? []: {};
for(let k in obj) {
let newKey = k.replace(searchvalue, newvalue);
if (typeof(obj[k]) === 'object') {
newObj[newKey] = Array.isArray(obj[k]) ? []: {};
replaceKeys(obj[k], searchvalue, newvalue, newObj[newKey])
} else {
newObj[newKey] = obj[k];
}
}
return newObj;
}
const result = replaceKeys(arr, /\./g, '_');
console.log('Result:', result);

Related

Getting the array name and values in Javacript Object

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);
}
}
}
}

Convert keys from key value pair to capital case using javaScript

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)

How to select specific properties of object where aren't null in ES6?

I want to select specific object properties where they aren't null.
I want to select id and name of this object:
{
"description": "hello",
"title": "Update",
"id": "1",
"name": null
}
expected output:
{
"id": "1",
// no name because it's null
}
I tried to do that using this code:
const { title, description, ...newValues } = values;
console.log(newValues);
You can filter all null elements by converting them to an entries array and then back to an object:
const filteredNewValues = Object.fromEntries(Object.entries(newValues).filter(e => e[1]))
Browser-Support is limited. So use a polyfill if you need to use it in old browsers. See here.
Grab all keys with Object.keys and then using reduce to get the selected property only that is not null.
You can use condition either obj[curr] or obj[curr] !== null
const obj = {
description: "hello",
title: "Update",
id: "1",
name: null,
};
const selected = ["id", "name"];
const result = Object.keys(obj).reduce((acc, curr) => {
if (selected.includes(curr) && obj[curr]) {
acc[curr] = obj[curr];
}
return acc;
}, {});
console.log(result);
let data = {
"description": "hello",
"title": "Update",
"id": "1",
"name": null
}
let filteredData = data.name && data.id ? {id: data.id, name: data.name} : undefined
Okay, let's assume that you want to make it in a dynamic way.
/**
* Get wanted properties of an object
* #param object
* #param {string[]} keys
*/
function cloneObject(obj, keys) {
return keys
.filter(key => obj[key] !== null)
.reduce((newObj, key) => {
newObj[key] = obj[key];
return newObj;
}, {});
}
// here you have your wanted keys
let keys = ['id', 'name'];
let object = {
"description": "hello",
"title": "Update",
"id": "1",
"name": null
};
let newObject = cloneObject(object, keys);
You could create a simple function to extract only non-null passed keys.
var data = {
"description": null,
"title": "Update",
"id": "1",
"name": false
};
function get(data, keys)
{
return keys.reduce((acc, cur) => {
return {...acc, ...(data[cur] !== undefined && data[cur] !== null && {[cur]: data[cur]})}
}, {});
}
console.log(get(data, ["description", "title", "id", "name", "fake"]));

Rearrange json files

I want to rearrange the following JSON which i am having trouble with. I want to convert a format of JSON object into the other for myself. Any help is appreciated. I Thank you.
From :
[
{"a":1,"b":2,"c":3,"d":4,"name":"chris"},
{"a":11,"b":21,"c":31,"d":41,"name":"chris1"},
{"a":12,"b":22,"c":32,"d":42,"name":"chris2"}
]
To:
[
{
"name": a,
"chris":1,
"chris1":11,
chris2:12
},
{
"name": b,
"chris":2,
"chris1":21,
chris2:22
},
{
"name": c,
"chris":3,
"chris1":31,
chris2:32
},
{
"name": d,
"chris":4,
"chris1":41,
chris2:42
}
]
Here's a snippet you could use
let json = [
{"a":1,"b":"2","c":3,"d":4,"name":"chris"},
{"a":11,"b":"21","c":31,"d":41,"name":"chris1"},
{"a":12,"b":"22","c":32,"d":42,"name":"chris2"}
]
let map = {};
for (const obj of json) {
for( const [key, value] of Object.entries(obj)) {
if (key === "name") continue;
if (typeof map[key] !== "object") {
map[key] = {name: key};
}
const data = map[key];
data[obj.name]= value;
}
}
console.log(map)

arrange array to become object array base on duplicate string

I have array and I want to arrange that to object array structure base on same string before dot, I want to create an object array structure to make it editable, so i can fill the value of each data on my array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"]
how can i arrange that to become object array structure
var arr = [ "data": {
"plmn": "",
"id": "",
"time": '',
"cell": {
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"earfcn": '',
"pci": '',
"celltiming": [
0,
1
],
"sinr": [
0,
1
]
},
"mac": ""
},
"time": '',
"deviceID": ""]
I want to create an object array so i can fill the value of each key
I've used the following:
Array.prototype.reduce(), accumulating over an empty object {},
A reference (ref) to the accumulator object,
String.prototype.split() to extract individual keys (substrings) from the current string in the array,
Iterating over the keys to progress along the key "chain",
a. If a key doesn't already exist in the accumulator object, create an object at that key, i.e. if (!ref[key]) ref[key] = {}
b. Continue to traverse the accumulator object by re-setting the reference (ref), i.e. ref = ref[key]
Move to the next string in the original array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
console.log(JSON.stringify(obj, null, "\t"));
This gets you most of the way. Now all you need to do is:
Traverse the object (first pass), replacing empty objects with empty strings, then
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
Traverse the object (second pass), checking when all of the keys of an object are numbers and all of the values are empty strings, and replacing this object with an array of the keys.
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
Complete solution: https://jsfiddle.net/s2attatz/1/
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
console.log(JSON.stringify(obj, null, "\t"));
/*
{
"data": {
"cell": {
"celltiming": [
0,
1
],
"earfcn": "",
"pci": "",
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"sinr": [
0,
1
]
},
"cells": {
"0": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"1": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"2": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"3": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
}
},
"id": "",
"mac": "",
"plmn": "",
"rssi": "",
"time": ""
},
"deviceID": "",
"time": ""
}
*/

Categories

Resources