Easiest way to interate over a complex JSON object via Javascript
Asked Answered
G

7

3

I'm consuming JSON data that has a bit of a weird structure for example:

{
    "RESULT": 
    {
        "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
        "DATA": [
                    [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                    [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
        ]
    },
    "ERROR": 0
}

I would like to create some JavaScript that would restructure this data to proper JSON structures so that the "Column" array values become the keys for the "DATA" array's values. So after a JS process is run the data resembles the following:

[
  {"ID":7,"name":"Site-A","ENABLED":1,"perms":"1,2","vcenabled":1,"vcvalue":1,"checkenabled":1,"checkvalue":1,"indxenabled":1,"indxvalue":1},
  {"ID":15,"name":"Site-B","ENABLED":1,"perms":"1,2","vcenabled":1,"vcvalue":1,"checkenabled":1,"checkvalue":1,"indxenabled":1,"indxvalue":1}

]

What are the JavaScript best practices for accomplishing the JSON restructuring? Could I accomplish this task using a JS framework like JQuery, Foundation JS, ect... ?

Gymnasiast answered 19/6, 2013 at 13:8 Comment(2)
you can accomplish this with a simple loop. Create an empty object, iterate through COLUMNS, get data from DATA and fill up your new object.Sentiment
@claustrofob: two loops for simplicity, please :-)Larrup
S
3

newjson is your new object, j is your json,

code is very fast as it caches the legth and don't uses push.

And as it's pure javascript it's faster than all the libraries.

var j={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var newjson=[],d=j.RESULT.COLUMNS.length;
for(var a=0,b=j.RESULT.DATA.length;a<b;a++){
 for(var c=0,tmpObj={};c<d;c++){
  tmpObj[j.RESULT.COLUMNS[c]]=j.RESULT.DATA[a][c];
 }
 newjson[a]=tmpObj;
}

console.log(newjson);

based on Bergi's response u can also use the while-- loop.

var orig={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var formatted = [],
data = orig.RESULT.DATA,
cols = orig.RESULT.COLUMNS,
l = cols.length,
f = data.length;

while (f--) {
  var d = data[f],
      o = {},
      g = l;
  while (g--) {
    o[cols[g]] = d[g];
  }
  formatted[f] = o;
}
Sigismondo answered 19/6, 2013 at 13:25 Comment(6)
Why do you think not using push makes it better? Btw, the code is very slow as it does not cache the relevant things.Larrup
newjson[a]=tmpObj; is faster than newjson.push(tmpObj).and what u wanna cache?Sigismondo
OK, if you have the index already available that will be better, but there's no relevant distinction between arr.push(x) and arr[arr.length] = x. See https://mcmap.net/q/37657/-why-is-array-push-sometimes-faster-than-array-n-value for detailed analysis - one should use what is clearer to read :-)Larrup
jsperf.com/reformat-json yeah it depends on browser, anyway good work with caching =)Sigismondo
i added now a while-- loop;)Sigismondo
Yeah, that might be faster, but it's getting less readable :-) +1 thoughLarrup
L
5

Using Underscore, it's a one-liner:

var formatted = _.map(orig.RESULT.DATA, _.partial(_.object, orig.RESULT.COLUMNS));

With plain javascript (less elegant but faster), it would be

var formatted = [],
    data = orig.RESULT.DATA,
    cols = orig.RESULT.COLUMNS,
    l = cols.length;
for (var i=0; i<data.length; i++) {
    var d = data[i],
        o = {};
    for (var j=0; j<l; j++)
        o[cols[j]] = d[j];
    formatted.push(o);
}
Larrup answered 19/6, 2013 at 15:54 Comment(0)
S
3

you can use underscore Array functions for this task

http://underscorejs.org/#arrays

uusing the object function would be helpful http://underscorejs.org/#object

from the documentation : _.object(list, [values]) Converts arrays into objects. Pass either a single list of [key, value] pairs, or a list of keys, and a list of values ..the example:

_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
 => {moe: 30, larry: 40, curly: 50}

here is the JSfiddle with the solution http://jsfiddle.net/rayweb_on/kxR88/1/

and the code looks like this for this specific scenario.

 var plain = {
"RESULT": 
{
    "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
    "DATA": [
                [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
    ]
},
"ERROR": 0
},

formatted = [];

_.each(plain.RESULT.DATA, function(value) {
    var tmp = {};
     tmp = _.object(plain.RESULT.COLUMNS,value)
    formatted.push(tmp);
});

 console.log(formatted);
Sporogonium answered 19/6, 2013 at 13:22 Comment(1)
Well, you really should use the appropriate array function :-)Larrup
S
3

newjson is your new object, j is your json,

code is very fast as it caches the legth and don't uses push.

And as it's pure javascript it's faster than all the libraries.

var j={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var newjson=[],d=j.RESULT.COLUMNS.length;
for(var a=0,b=j.RESULT.DATA.length;a<b;a++){
 for(var c=0,tmpObj={};c<d;c++){
  tmpObj[j.RESULT.COLUMNS[c]]=j.RESULT.DATA[a][c];
 }
 newjson[a]=tmpObj;
}

console.log(newjson);

based on Bergi's response u can also use the while-- loop.

var orig={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var formatted = [],
data = orig.RESULT.DATA,
cols = orig.RESULT.COLUMNS,
l = cols.length,
f = data.length;

while (f--) {
  var d = data[f],
      o = {},
      g = l;
  while (g--) {
    o[cols[g]] = d[g];
  }
  formatted[f] = o;
}
Sigismondo answered 19/6, 2013 at 13:25 Comment(6)
Why do you think not using push makes it better? Btw, the code is very slow as it does not cache the relevant things.Larrup
newjson[a]=tmpObj; is faster than newjson.push(tmpObj).and what u wanna cache?Sigismondo
OK, if you have the index already available that will be better, but there's no relevant distinction between arr.push(x) and arr[arr.length] = x. See https://mcmap.net/q/37657/-why-is-array-push-sometimes-faster-than-array-n-value for detailed analysis - one should use what is clearer to read :-)Larrup
jsperf.com/reformat-json yeah it depends on browser, anyway good work with caching =)Sigismondo
i added now a while-- loop;)Sigismondo
Yeah, that might be faster, but it's getting less readable :-) +1 thoughLarrup
G
2

Try this using underscorejs.

var plain = {
    "RESULT": 
    {
        "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
        "DATA": [
                [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
        ]
    },
    "ERROR": 0
}
   , formatted = [];

_.each(plain.RESULT.DATA, function(value) {
    var tmp = {};
    _.each(value, function(parameter, pos) {
        tmp[plain.RESULT.COLUMNS[pos]] = parameter;
    });
    formatted.push(tmp);
});

console.log(formatted);

http://jsfiddle.net/kxR88/

Ganger answered 19/6, 2013 at 13:30 Comment(2)
Why do you use slow each functions instead of for-loops? The Underscore approach looks different.Larrup
Yip, your underscore one-liner looks better. Nice one with the _.partial, never used this.Ganger
R
2

Actually, you could use a combination of Array#map for the array and Array#reduce for the objects with the new properties

var data = { RESULT: { COLUMNS: ["ID", "name", "ENABLED", "perms", "vcenabled", "vcvalue", "checkenabled", "checkvalue", "indxenabled", "indxvalue"], DATA: [[7, "Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0], [15, "Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]] }, ERROR: 0 },
    result = data.RESULT.DATA.map(function (a) {
        return a.reduce(function (o, d, i) {
            o[data.RESULT.COLUMNS[i]] = d;
            return o;
        }, {});
    });

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

With ES6, you could use Object.assign with spread syntax ....

Object.assign adds properties to the given object and returns this object.

Spread syntax ... takes an array and insert the elements as parameters to the function.

var data = { RESULT: { COLUMNS: ["ID", "name", "ENABLED", "perms", "vcenabled", "vcvalue", "checkenabled", "checkvalue", "indxenabled", "indxvalue"], DATA: [[7, "Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0], [15, "Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]] }, ERROR: 0 },
    result = data.RESULT.DATA.map(a =>
        Object.assign(...data.RESULT.COLUMNS.map((k, i) => ({ [k]: a[i] }))));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ramentum answered 5/9, 2017 at 10:28 Comment(0)
A
0

Using JQuery:

function jsonToObj(json){
   return jQuery.parseJSON(JSON.stringify(json));
}

For example, after a GET request the server send a complex object

  $.get("/Files/-2", function (rxData, status) {

      var obj = jsonToObj(rxData);
      console.log(obj);
  });

Logged in console, can be explored through Chrome's Web Developer (F12), in my case looks like this:

image showing nested levels

Angloamerican answered 10/10, 2019 at 14:36 Comment(0)
A
0

By simple JS, your solution would look like this:

var yourObj = {
  "RESULT": {
    "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
    "DATA": [
      [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
      [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
    ]
  },
  "ERROR": 0
}

//Solution

var finalARR = [];

var colLength = yourObj.RESULT.COLUMNS.length;
var dataLength = yourObj.RESULT.DATA.length;

for (var i = 0; i < dataLength; i++) {
  var finalJSON = {};
  for (var j = 0; j < colLength; j++) {
    finalJSON[yourObj.RESULT.COLUMNS[j]] = yourObj.RESULT.DATA[i][j];
  }
  finalARR[i] = finalJSON;
}

console.log(finalARR);
Alkalosis answered 27/7, 2020 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.