Convert a string key in a JSON object to a child object? - javascript

I've looped through an document.form.element the names are constructed into an array name like so:
Current output
Some of the names of they keys are like so in JSON:
{
data[name]: "foo",
data[address]: "baz drive",
data[city]: "Dallas",
data[state]: "Texas",
data[phone]: "555-1212"
}
Desired output
Is there a way to convert it to this with Pure JavaScript (and without frameworks like jQuery) without using eval?:
{
data: {
name: "foo",
address: "baz drive",
city: "Dallas",
state: "Texas",
phone: "555-1212"
}
}
What have i tried so far
<script type="javascript">
var o = {
data[name]: "foo",
data[address]: "baz drive",
data[city]: "Dallas",
data[state]: "Texas",
data[phone]: "555-1212"
}
var temp = [];
for (key in o) {
temp[JSON.parse(key)] = o;
}
</script>
Fiddle is here: http://jsfiddle.net/chrisjlee/medbzv9a/
Or is this not totally possible?

Do like
var o = {
"data[name]": "foo",
"data[address]": "baz drive",
"data[city]": "Dallas",
"data[state]": "Texas",
"data[phone]": "555-1212"
};
o.data = {};
for (key in o) {
var index = key.match(/[^[\]]+(?=])/g);
if(index) {
o.data[index] = o[key];
delete(o[key]);
}
}
console.log(o);
Here is a sample fiddle.

The following function should fix the object. It will be executed recursively and it can handle arrays too.
var fixKeys = function(obj) {
if (typeof(obj) != "object")
return obj;
if (Object.prototype.toString.call(obj) == "[object Array]")
return obj.map(arguments.callee);
var newObj = {};
for (var key in obj) {
if (!obj.hasOwnProperty(key))
continue;
var m = /^(\w+)\[(\w+)\]$/.exec(key);
if (m) {
newObj[m[1]] = newObj[m[1]] || {};
newObj[m[1]][m[2]] = arguments.callee(obj[key]);
} else {
newObj[key] = arguments.callee(obj[key]);
}
}
return newObj;
};
Fiddle
And here's an even better version, which can handle data of this type:
var o = {
"data[name]": "foo",
"data[address][street]": "baz drive",
"data[address][city]": "Dallas",
"data[address][state]": "Texas",
"data[phone]": "555-1212",
someArray: [
{"test[a]": 42},
42
]
};
Just in case you need it:
var fixKeys = function(obj) {
if (typeof(obj) != "object")
return obj;
if (Object.prototype.toString.call(obj) == "[object Array]")
return obj.map(arguments.callee);
var newObj = {};
for (var key in obj) {
if (!obj.hasOwnProperty(key))
continue;
var m = /^(\w+)(?:\[\w+\])+$/.exec(key);
if (m) {
var subKey = key.substr(m[1].length);
var subObj = newObj[m[1]] = newObj[m[1]] || {};
while (m = /^\[(\w+)\]\[/.exec(subKey)) {
subObj = subObj[m[1]] = subObj[m[1]] || {};
subKey = subKey.substr(m[0].length - 1);
}
m = /^\[(\w+)\]$/.exec(subKey);
subObj[m[1]] = arguments.callee(obj[key]);
} else {
newObj[key] = arguments.callee(obj[key]);
}
}
return newObj;
};
Fiddle

Related

Get path to JSON object by key?

Given the following object:
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
We're trying to find the path of myInventory, the issue is that the children's uuid will be different each time. Any idea how we can get the path to myInventory by providing it as a key and get the json path to it?
If things are dynamic, a programmatic key search could help
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
const getPath = (key, o) => {
if (!o || typeof o !== "object") {
return "";
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return key;
}
const path = getPath(key, o[keys[i]]);
if (path) {
return keys[i] + "." + path;
}
}
return "";
};
const getValueForKey = (key, o) => {
if (!o || typeof o !== "object") {
return undefined;
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return o[key];
}
const value = getValueForKey(key, o[keys[i]]);
if (value) {
return value;
}
}
return undefined;
}
console.log(getPath("myInventory", ourObject))
console.log(getValueForKey("myInventory", ourObject))
Not sure if I understand the question right but
let uuid = '2165d20a-6276-468f-a02f-1abd65cad618';
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory
var changingKey = Object.keys(ourObject["payload"]["streams"][0]["children"])[0];
console.log(ourObject["payload"]["streams"][0]["children"][changingKey]["additionalInformation"]["myInventory"]);
Okay, you could create a helper function that gets the UUID. Since it's an object, the lookup is close to O(1) especially given the case that the children has only one key-value pair here.
function getUUIDFromPayload(payload) {
let obj = payload.streams[0].children
let uuid = Object.keys(obj)[0]
return uuid
}
Usage
const uuid = getUUIDFromPayload(payload)
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory

Convert from one object type to a different object type while preserving the data

I have an object, Object1 which is the Datamodel for AngularForms Where all the Form functionality has been built using this Model and changing the model is not feasible at this stage.
An Api is requesting the data in format of Object2, to send the data to API I have to copy all the data in Object1 to Object2.
The two objects are as below: just a sample on how different two objects are
object1 = {
applicant: {
name : "Abc",
title : "Mr.",
addr1 : "",
addr2 : "",
email : "someone#example.com"
},
nominee: {
name : "Def",
title : "Ms.",
addr1 : "",
email : "sometwo#example.com",
mobile : ""
},
...
}
and
object2 = {
"key1_1": "Abc",
"key1_2": "Mr.",
"key1_3": "",
"key1_4": "",
"key1_5": "someone#example.com",
"key2_1": "Def",
"key2_2": "Ms.",
"key2_3": "",
"key2_4": "sometwo#example.com",
"key2_5": "",
...
}
I want to able to convert from 1st Object to 2nd Object.I have written function as below. So, calling the function and passing the Object1 as param return Object2 and vice versa.
function convertToObj2(object1){
obj2 = {
key1_1 : object1.applicant.name,
key1_2 : object1.applicant.title,
key1_3 : object1.applicant.addr1,
key1_4 : object1.applicant.addr2,
key1_5 : object1.applicant.email,
key2_1 : object1.nominee.name,
key2_2 : object1.nominee.title,
key2_3 : object1.nominee.addr1,
key2_4 : object1.nominee.email,
key2_5 : object1.nominee.mobile,
...
}
return obj2;
}
function convertToObj1(object2){
obj1 = {
applicant: {
name : object2.key1_1,
title : object2.key1_2,
addr1 : object2.key1_3,
addr2 : object2.key1_4,
email : object2.key1_5
},
nominee: {
name : object2.key2_1,
title : object2.key2_2,
addr1 : object2.key2_3,
email : object2.key2_4,
mobile : object2.key2_5
},
...
}
return obj1;
}
Is there a better way to map these objects to each other, without manually assigning each value to the key, as it is tedious and each object contains 300+ keys?
Note: names of keys are not as shown in exapmle, they are normal words without undersorce and not in alpha order.
function convertToObj2(object1){
var tmpObj = {};
var keys = Object.keys(object1);
for(keyName of keys){
tmpObj = Object.assign(tmpObj,object1[keyName]);
}
return tmpObj;
}
Call This Function to convert object1 to object2.
The only way I can think of to map key value properties from object1 to object2 without manually writing them out line by line is by using a for in loop or for loop with Object.keys(obj).
You can also look at lodash, jQuery or other frontend utility libraries. They generally have helper functions for handling these sort of tasks.
When converting, you want to add a prefix/suffix to each of the keys so that you can convert back and forth between the two object types and also to identify which object type you are dealing with.
I don't really recommend using a for in loop, but hopefully the example below will give you some ideas on a conceptual level.
function convertToObj2(obj1) {
var obj2Prefix = "__obj2__",
result = {};
var key;
for (key in obj1) {
if (obj1.hasOwnProperty(key)) {
// Add the prefix to new obj2 key
// for identification purposes
result[obj2Prefix + key] = obj1[key];
}
}
return result;
}
Hope this helps :)
Maybe this solves your problem (using jquery):
function convertToObj2(object1) {
var object2 = {};
$.each(object1, function(key, obj) {
$.each(obj, function(key1, val1) {
object2[key1] = val1;
});
});
return object2;
}
function convertToObj1(object2) {
var object1 = {};
$.each(object2, function(key, val) {
var obj1Key = key.substring(0, key.indexOf('_'));
var obj = {};
obj[key] = val;
if (object1[obj1Key] != null) {
object1[obj1Key][key] = val;
} else {
object1[obj1Key] = obj;
}
});
return object1;
}
var object2 = {
key1_1: "value 1_1",
key1_2: "value 1_2",
key1_3: "value 1_3",
key1_4: "value 1_4",
key1_5: "value 1_5",
key2_1: "value 2_1",
key2_2: "value 2_2",
key2_3: "value 2_3",
key2_4: "value 2_4",
key2_5: "value 2_5",
};
var object1 = {
key1: {
key1_1: "value 1_1",
key1_2: "value 1_2",
key1_3: "value 1_3",
key1_4: "value 1_4",
key1_5: "value 1_5",
},
key2: {
key2_1: "value 2_1",
key2_2: "value 2_2",
key2_3: "value 2_3",
key2_4: "value 2_4",
key2_5: "value 2_5",
}
};
$(function() {
console.log(convertToObj2(object1));
console.log(convertToObj1(object2));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Thanks for everyone who spent their valuable time finding a solution.
I have solved this with reference to this answer.
Step 1 : created a relation for each key in both the objects
relationArr =
[
["applicant.name", "key1_1" ],
["applicant.title", "key1_2" ],
["applicant.addr1", "key1_3" ],
["applicant.addr2", "key1_4" ],
["applicant.email", "key1_5" ],
["nominee.name", "key2_1" ],
["nominee.title", "key2_2" ],
["nominee.addr1 ", "key2_3" ],
["nominee.email", "key2_4" ],
["nominee.mobile", "key2_5" ],
...
]
Step 2 : create a function to add/read a property by key-name enclosed "quotes"
function add_property(returnObj, key, sourceObj, srcKey) {
if (key == null || key == "null"){
return;
}
var keys = key.split('.');
while (keys.length > 1) {
var k = keys.shift();
if (!returnObj.hasOwnProperty(k)) {
returnObj[k] = {};
}
returnObj = returnObj[k];
}
returnObj[keys[0]] = this.read_property(sourceObj, srcKey);
}
function read_property(sourceObj, key) {
if (key == null || key == "null"){
return null;
}
var keys = key.split('.');
while (keys.length > 1) {
var k = keys.shift();
sourceObj = sourceObj[k];
}
return sourceObj[keys[0]] != undefined ? sourceObj[keys[0]] : "";
}
Step 3 : Create a function that takes a source-object and return the converted Object w.r.t relationArr, here fromIndex and toIndex specifies the direction of conversion
function convertObject(relObj, sourceObj, fromIndex, toIndex){
var returnObj = {};
for (var i = 0, len = relObj.length; i < len; i++) {
this.add_property(returnObj, relObj[i][toIndex], sourceObj, relObj[i][fromIndex] )
}
return returnObj;
}
So, in this way if I specify the relation of keys once, I am to convert object types, I have added only two object types in relation, If there are more objects just add key of the other object ["applicant.name", "key1_1", "newkey" ], to the relation and will be able to convert
relationArr = [
["applicant.name", "key1_1"],
["applicant.title", "key1_2"],
["applicant.addr1", "key1_3"],
["applicant.addr2", "key1_4"],
["applicant.email", "key1_5"],
["nominee.name", "key2_1"],
["nominee.title", "key2_2"],
["nominee.addr1 ", "key2_3"],
["nominee.email", "key2_4"],
["nominee.mobile", "key2_5"]
]
function add_property(returnObj, key, sourceObj, srcKey) {
if (key == null || key == "null") {
return;
}
var keys = key.split('.');
while (keys.length > 1) {
var k = keys.shift();
if (!returnObj.hasOwnProperty(k)) {
returnObj[k] = {};
}
returnObj = returnObj[k];
}
returnObj[keys[0]] = this.read_property(sourceObj, srcKey);
}
function read_property(sourceObj, key) {
if (key == null || key == "null") {
return null;
}
var keys = key.split('.');
while (keys.length > 1) {
var k = keys.shift();
sourceObj = sourceObj[k];
}
return sourceObj[keys[0]] != undefined ? sourceObj[keys[0]] : "";
}
function convertObject(relObj, sourceObj, fromIndex, toIndex) {
var returnObj = {};
for (var i = 0, len = relObj.length; i < len; i++) {
this.add_property(returnObj, relObj[i][toIndex], sourceObj, relObj[i][fromIndex])
}
return returnObj;
}
// Converting from Object1 Type to Object2 Type
object1 = {
applicant: {
name: "Abc",
title: "Mr.",
addr1: "",
addr2: "",
email: "someone#example.com"
},
nominee: {
name: "Def",
title: "Ms.",
addr1: "",
email: "sometwo#example.com",
mobile: ""
},
}
convertedObject2 = convertObject(relationArr, object1, 0, 1);
console.log(convertedObject2); // prints generated Object2 from Object1
//Converting Object2 Type to Object1
convertedObject1 = convertObject(relationArr, convertedObject2, 1, 0);
console.log(convertedObject1); // prints generated Object1 Converted from Object2
You can use array#reduce.
var object1 = { key1: { key1_1: "value 1_1", key1_2: "value 1_2", key1_3: "value 1_3", key1_4: "value 1_4", key1_5: "value 1_5", }, key2: { key2_1: "value 2_1", key2_2: "value 2_2", key2_3: "value 2_3", key2_4: "value 2_4", key2_5: "value 2_5", } },
object2 = { key1_1: "value 1_1", key1_2: "value 1_2", key1_3: "value 1_3", key1_4: "value 1_4", key1_5: "value 1_5", key2_1: "value 2_1", key2_2: "value 2_2", key2_3: "value 2_3", key2_4: "value 2_4", key2_5: "value 2_5"};
var object1ToObject2 = (o) => {
return Object.keys(o).reduce((r, k) => Object.assign(r,o[k]),{});
}
var object2ToObject1 = (o) => {
return Object.keys(o).reduce((r,k) => {
var key = k.split('_')[0];
r[key] = r[key] || {};
r[key][k] = o[k];
return r;
},{});
}
console.log(object1ToObject2(object1));
console.log(object2ToObject1(object2));

Cleaning up a JSON object that is full of objects with 1 attribute

I have a JSON object that's formatted like the following:
{
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
}
and this format holds for dozens of attributes. I'm looking for a way to have the JSON be more like:
{
"ATTR1": "Value1",
"ATTR2": "Value2" //and so on
}
Is there an easy way to do this in Javascript? I've tried something like:
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
attr = attr[0];
}
}
But this hasn't been working. Any ideas?
Use reduce on the object's keys for that:
let foo = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
};
let res = Object.keys(foo).reduce((a,b) => {
a[b] = foo[b]['0'];
return a;
}, {});
console.log(res)
If you want to mutate the original obj, you can do this:
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
obj[attr] = obj[attr][0];
}
}
you are close!
Try something like this:
var obj = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
};
var obj2 = {};
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
obj2[attr] = obj[attr][0];
}
}
alert(JSON.stringify(obj2));
Fiddle: https://jsfiddle.net/coLxfeum/
Iterating over javascript objects is easier using Object.keys(), IMO. It's supported in the major browsers... Anyway, you want to iterate over the top level object, grabbing all of it's "smallObject" values and flatten them. You can make the checks as strict as you like (insisting on "0" keys etc), but fundamentally, it seems important that the values you are collapsing are single-value objects containing string values? Anyway - here's how you could do that:
var v1 = {
"ATTR1": {
"0": "Value1"
},
"ATTR2": {
"0": "Value2"
}
}
function flatten(obj) {
Object.keys(obj).forEach( function(attr) {
var smallObj = obj[attr];
var keys = Object.keys(smallObj);
if( keys.length === 1 && typeof smallObj[keys[0]] === 'string' ) { // && keys[0] === "0" ?
obj[attr] = smallObj[keys[0]];
} // else throw Error(...) ?
})
return obj;
}
console.log(flatten(v1));
> { ATTR1: 'Value1', ATTR2: 'Value2' }
Try this :
var jsonObj = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
}
};
var newJson = {};
for(var i = 0;i<Object.keys(jsonObj).length;i++) {
newJson[Object.keys(jsonObj)[i]] = jsonObj[Object.keys(jsonObj)[i]]["0"];
}
console.log(newJson);

Javascript convert object with array string keys to key/name value's

I have an object with named keys like this
{
'name[first]': 'john',
'name[last]': 'doe'
}
that I want to convert to:
{
'name' : {
'first' : 'john',
'last' : 'doe'
}
}
Any idea on an elegent way to do this?
You can use reduce() to return obj and regular expression to split key.
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var result = Object.keys(obj).reduce(function(r, e) {
var key = e.split(/\[(.*?)\]/)
if (!r[key[0]]) r[key[0]] = {}
r[key[0]][key[1]] = obj[e]
return r;
}, {})
console.log(result)
For nested key structure you could again use reduce but with different approach to keys but then you face problem of deep merge of object and for that you can use lodash.
var obj = {
'name[first[foo]]': 'john',
'name[last]': 'doe',
'name[last[foo[bar]]]': 'doe'
}
var result = Object.keys(obj).reduce(function(r, e) {
var key = e.replace(/\[/g, '.').replace(/\]/g, '').split('.')
var o = {}
key.reduce(function(re, el, i) {
return i != key.length - 1 ? re[el] = {} : re[el] = obj[e]
}, o)
r = _.merge(r, o)
return r;
}, {})
console.log(JSON.stringify(result, 0, 4))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Using a for..in loop and constructing a new object:
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
};
var newObj = {}
for (var key in obj) {
var parts = key.split(/\[|\]/);
if(!newObj.hasOwnProperty(parts[0]))
newObj[parts[0]] = {};
newObj[parts[0]][parts[1]] = obj[key];
}
console.log(newObj);
The solution using Object.keys, Array.prototytpe.reduce and String.prototype.match functions:
var obj = {'name[first]': 'john', 'name[last]': 'doe'};
var result = Object.keys(obj).reduce(function (o, key) {
var parts = key.match(/^(\w+)\[(\w+)\]$/);
if (!o[parts[1]]) {
o[parts[1]] = {};
}
o[parts[1]][parts[2]] = obj[key];
return o;
}, {});
console.log(result);
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var newObj = {};
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var keys = property.match(/(\w+)/g);
if (keys && keys.length == 2) {
newObj[keys[0]] = newObj[keys[0]] || {};
newObj[keys[0]][keys[1]] = obj[property];
}
}
}
console.log(newObj);
You can try the following:
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var result = Object.keys(obj).reduce(function(newObj, prop) {
var key = prop.split(/\[|\]/)[1];
newObj[key] = obj[prop];
return newObj;
}, {})
console.log(result);

How can get the property name of an object array value?

I have an object like below:
myObj = {
"name":"John",
"age":30,
"cars":[ "Ford", "BMW", "Fiat" ]
}
How can I know the property name "cars" when I input "BMW"? I need a function which needs to return property name "cars" when I pass the argument "BMW" in the function.
function getKeyByitem(myObj, value)
for (var key in myObj) {
if (myObj.hasOwnProperty(key) && Array.isArray(myObj[key])) {
if(myObj[key].indexOf(value) != -1){
return key;
}
}
}
}
var key = getKeyByitem(myObj, 'BMW');
here is demo https://plnkr.co/edit/wVFGcAKuml4rWuIaMx2K?p=preview
myObj = {
"name":"John",
"age":30,
"cars":[ "Ford", "BMW", "Fiat" ]
}
var findKey = function (str) {
var keys = Object.getOwnPropertyNames(myObj);
var key = null;
var match = keys.some(function (k) {
key = k;
var val = myObj[key];
if (Array.isArray(val)) {
return val.indexOf(str) >= 0;
} else {
return val.toString() === str;
}
return false;
});
if (match) return key;
}
console.log(findKey('BMW')); // 'cars'
console.log(findKey('John')); // 'name'
console.log(findKey('30')); // 'age'
Hope this helps!
You cna do something like this
var myObj = {
"name": "John",
"age": 30,
"cars": ["Ford", "BMW", "Fiat"]
}
var getKey=function(elem) {
var toReturn = '';
for (var k in myObj) { // loop through the object
if(Array.isArray(myObj[k])){
if(myObj[k].indexOf(elem) !== -1){
toReturn = k;
}
}
else{
if(myObj[k] === elem){
toReturn = k
}
}
}
return toReturn;
}
console.log(getKey('BMW'))
DEMO

Categories