1

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?

2
  • @melpomene if you could write a code or function to me, it will be awesome or any solution to me how to convert? Commented Apr 3, 2018 at 11:48
  • That's not what SO is for. If you want someone to write code for you, hire a programmer. Commented Apr 3, 2018 at 11:48

3 Answers 3

2

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)

Sign up to request clarification or add additional context in comments.

4 Comments

it's look like what i want; but what is new create[type]?
Updated so now value types work before everything was string.
Well it will create new instance of data type you have in your object, so for array it will create new array, string => new String ...
If its false we need to hardcode false because new Boolean('false') = true
2

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

Comments

1
  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;

3 Comments

please note that this script uses a newer JS format, you might have to downgrade the syntax
@zedling fetched from Redis -> nodejs -> ES7
tnx, it will be run in node.js environment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.