Most elegant way to create a JSON Object

Viewed 154

I hava a javacript object that look like this.

val = 
{
default: "version1"
version1: "abc.com"
version2: "def.com"
...
versionn:"xyz.com"
}

I want to convert this to a nested json like this

"newval": {
"website": {
    "url": "abc.com"
},
"versions": {
    "version1": {
        "website": {
            "url": "abc.com"
        }
    },
    "version2": {
        "website": {
            "url": "def.com"
        }
    }
}

}

My version uses a lot if if statements and unnecessary variables. Is there an elegant way to convert/create this JSON.

i.e the default version is the one that comes under newval.website and all the version data is the value fir newval.website.versions

5 Answers

Setting the .website property is pretty simple. Just a matter of looking up the key that default holds.

The other part can be done by filtering out the default key, and then mapping the remaining ones to a new list of objects that are assigned to the result using Object.assign.

var val =  {
default: "version1",
version1: "abc.com",
version2: "def.com",
version3:"xyz.com"
};

var res = {
  website: {url: val[val.default]},
  versions: Object.assign(
    ...Object.keys(val)
             .filter(k => k !== "default")
             .map(k => ({[k]: {website: {url: val[k]} } }))
)};

console.log(res);


Here's another way that avoids needing the .filter(). It assumes you don't mind making default non-enumerable on the original object.

var val =  {
default: "version1",
version1: "abc.com",
version2: "def.com",
version3:"xyz.com"
};

var res = {
  website: {url: val[Object.defineProperty(val, "default", {enumerable:false}).default]},
  versions: Object.assign(
    ...Object.keys(val).map(k => ({[k]: {website: {url: val[k]} } }))
)};

console.log(res);

The property is still configurable, so you could reset it if desired.


Or using .entries() instead of .keys() with parameter destructuring in the .map() callback.

var val =  {
default: "version1",
version1: "abc.com",
version2: "def.com",
version3:"xyz.com"
};

var res = {
  website: {url: val[Object.defineProperty(val, "default", {enumerable:false}).default]},
  versions: Object.assign(
    ...Object.entries(val).map(([k, v]) => ({[k]: {website: {url: v} } }))
)};

console.log(res);

My version:

var val = {
  default: 'version1',
  version1: 'abc.com',
  version2: 'def.com',
  version3: 'xyz.com'
}

var res = {
  website: {url: val[val.default]},
  versions: Object.entries(val).reduce(function(a, [k, v]) {
    if (k != 'default') a[k] = {website: {url: v}}
    return a
  }, {})
}

console.log(res)

And here's my version, just reducing the entries directly into the websites property, excluding the default property

var val = {
  default: "version1",
  version1: "abc.com",
  version2: "def.com",
  versionn: "xyz.com"
}

var result = {
  newval   : {website : val.default},
  versions : Object.entries(val).reduce((a,b)=>((b[0] != 'default'?a[b[0]]={website:b[1]}:0),a),{})
};

console.log(result)

You could assign the part for default directly and the rest by iterating the keys and assigning to the object.

var values = { default: "version1", version1: "abc.com", version2: "def.com", versionn: "xyz.com" },
    result = {
        newval: {
            website: { url: values[values.default] },
            versions: Object.assign(...Object.keys(values).map(k => k === 'default'
                ? {}
                : { [k]: { website: { url: values[k] } } }))
        }
    };


console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

A bit more efficient and compatible without function call:

val = { default:"version1", version1:"abc.com", version2:"def.com", versionn:"xyz.com" }

newval = { website: { url: val[val.default] }, versions: { } }

for (k in val)
  if (k !== 'default')
    newval.versions[k] = { website: { url: val[k] } }

console.log({newval})

Related