Reputation: 61
i have this type of object which fetched from Redis
{
'username': 'hamet',
'username_Type': 'string',
'meta': 'object',
'meta_Type': 'object',
'meta.avatar': '/avatar.png',
'meta.avatar_Type': 'string',
'meta.active': 'false',
'meta.active_Type': 'boolean',
'meta.someArr': 'array',
'meta.someArr_Type': 'array',
'meta.someArr.0': 'object',
'meta.someArr.0_Type': 'object',
'meta.someArr.0.field': '123',
'meta.someArr.0.field_Type': 'number',
'meta.someArr.1': 'object',
'meta.someArr.1_Type': 'object',
'meta.someArr.1.field': '321',
'meta.someArr.1.field_Type': 'number'
}
all i want is convert this object to valid object like this:
{
username: 'hamet',
meta: {
avatar: '/avatar.png',
active: false,
someArr: [
{ field: 123 },
{ field: 321 }
]
}
}
once i created iterated function, but there was a problem with that. is it possible to convert with Iterated function and how?
Upvotes: 1
Views: 73
Reputation: 191976
Get an array of keys with Object.keys()
. Filter out the _Type
keys. Sort the keys to ensure that parents (shorter) keys are first, since keys` order in an object is not ensured.
Reduce the array of keys, and for each key get it's value by type. If the type is not object/array use the actual key value. Iterate the result object with Array.forEach()
, until you get to the leaf. Add the key with the value.
const obj = {"meta.someArr.1.field":"321","username":"hamet","username_Type":"string","meta":"object","meta_Type":"object","meta.avatar":"/avatar.png","meta.avatar_Type":"string","meta.active":"false","meta.active_Type":"boolean","meta.someArr":"array","meta.someArr_Type":"array","meta.someArr.0":"object","meta.someArr.0_Type":"object","meta.someArr.0.field":"123","meta.someArr.0.field_Type":"number","meta.someArr.1":"object","meta.someArr.1_Type":"object","meta.someArr.1.field_Type":"number"};
const byType = {
object: Object,
array: Array
};
const result = Object.keys(obj)
.filter((k) => !k.includes('_Type')) // remove Type keys
.sort((a, b) => a.length - b.length) // ensures that shorter (parent) keys are first
.reduce((r, k) => {
const type = obj[`${k}_Type`];
const valueByType = byType[type] && byType[type]();
const value = valueByType ? valueByType : obj[k];
const keys = k.split('.');
let current = r;
keys.forEach((key, i) => {
if(!(key in current)) current[key] = value;
else current = current[key];
});
return r;
}, {});
console.log(result);
Upvotes: 2
Reputation: 122027
You could create object with value types that you will use for creating new instances of different data types and then use reduce()
method to build your object.
const data = {"username":"hamet","username_Type":"string","meta":"object","meta_Type":"object","meta.avatar":"/avatar.png","meta.avatar_Type":"string","meta.active":"false","meta.active_Type":"boolean","meta.someArr":"array","meta.someArr_Type":"array","meta.someArr.0":"object","meta.someArr.0_Type":"object","meta.someArr.0.field":"123","meta.someArr.0.field_Type":"number","meta.someArr.1":"object","meta.someArr.1_Type":"object","meta.someArr.1.field":"321","meta.someArr.1.field_Type":"number"}
const result = {}
const create = {'string': String,'number': Number,'boolean': Boolean,'array': Array,'object': Object}
const findType = (key, obj) => obj[key]
Object.keys(data).forEach(key => {
if (!key.includes('Type')) {
key.split('.').reduce((r, e, i, arr) => {
let type = findType(key + '_Type', data);
let value = create[data[key]] || arr[i + 1] ? new create[type] : new create[type](data[key]).valueOf()
if (data[key] == 'false') value = false
r[e] = r[e] || value;
return r[e]
}, result)
}
})
console.log(result)
Upvotes: 2
Reputation: 138257
const result = {};
function apply(obj, value, key, ...keys) {
if(keys.length) {
apply(obj[key] || (obj[key] = {}), value ...keys);
} else {
obj[key] = value;
}
}
for(const [key, value] of Object.entries(yourObj))
apply(result, value, ...key.split("."));
You could use a recursive approach to generate the nested structure. I havent included a check if key is a number so that it creates an array, thats your job ;)
If you prefer functional programming:
const apply = (obj, value, ...keys) => keys.slice(1).reduce((obj, key) => obj[key] || (obj[key] = {}), obj)[keys.pop()] = value;
Upvotes: 1