0

I have data that looks like this.....

    errorTypes = ["newview","oldview","noview","someview"]
    var myData = [
      [{
        "timeBucket": 1472058000000,
        "errors": 534,
        "errorFree": 0,
        "business": 0,
        "errorRate": 1.0,
        "breakdown": [{
          "type": "newview",
          "count": 359,
          "errorRate": 1.0
        }, {
          "type": "oldview",
          "count": 169,
          "errorRate": 1.0
        }, {
          "type": "noview",
          "count": 6,
          "errorRate": 1.0
        }]
      }],
      [{
        "timeBucket": 1472061600000,
        "errors": 537,
        "errorFree": 0,
        "business": 0,
        "errorRate": 1.0,
        "breakdown": [{
          "type": "newview",
          "count": 338,
          "errorRate": 1.0
        }, {
          "type": "oldview",
          "count": 184,
          "errorRate": 1.0
        }, {
          "type": "noview",
          "count": 14,
          "errorRate": 1.0
        }, {
          "type": "someview",
          "count": 1,
          "errorRate": 1.0
        }]
      }]
    ];

I started deconstructing the JSON by the methodology below but it gives me multiple objects which is what the original is so I think it's probably headed the wrong way... (with timeBucket as the first element)

var result = [];

errorTypes.map( function (item) {
myData.forEach(function(ele, idx) {
  var count = ele[0].breakdown.filter(function(ele, idx) {
    return ele.type == item;
  })[0];
  count = (count === undefined) ? 0 : +count.count
  result.push(
    [ele[0].timeBucket, parseFloat(ele[0].errors), count]);
  });

});

console.log(result);

Results in ....

[[1472058000000, 534, 359], [1472061600000, 537, 338], [1472058000000, 534, 169], [1472061600000, 537, 184], [1472058000000, 534, 6], [1472061600000, 537, 14], [1472058000000, 534, 0], [1472061600000, 537, 1]]

and what I am needing to create is a table that looks like this....

<TABLE BORDER=1>
<TR><TD>Error</TD><TD>1472058000000</TD><TD>1472061600000</TD></TR>
<TR><TD>newview</TD><TD>359</TD><TD>338</TD></TR>
<TR><TD>oldview</TD><TD>169</TD><TD>184</TD></TR>
<TR><TD>noview</TD><TD>6</TD><TD>14</TD></TR>
<TR><TD>someview</TD><TD>0</TD><TD>1</TD></TR>
<TR><TD>TOTALS</TD><TD>534</TD><TD>537</TD></TR>
</TABLE>

I do have a JSFiddle here: https://jsfiddle.net/wilkiejane/1k1tbmxy/

Normally, being a novice Python developer, I'd just use pandas on it and be done but our HTML developer took another job and so now I'm the IT "team". :-( I don't need to do any sort of tabulation, it's just a sorting of the data and a whole series of anonymous arrays just confuses the heck out of me. Anyone have any advice on how I can solve this? Many, many thanks! JW

Jane Wilkie
  • 1,703
  • 3
  • 25
  • 49

3 Answers3

1

I realise you have a solution in the mean time, but I would still like to post the following code which uses some ES6 features:

// Create 2D array:
var arr = [
    ["Errors", ...myData.map( ([rec]) => rec.timeBucket )], 
    ...errorTypes.map( type => 
        [type,...myData.map( ([rec]) => 
            (rec.breakdown.find( err => err.type == type ) || {}).count || 0 )]), 
    ["TOTALS", ...myData.map( ([rec]) => rec.errors ) ]];

// Convert 2D array to HTML string:
var tbl = `<TABLE>
${arr.map( row => `<TR>${row.map( cell => `<TD>${cell}</TD>` ).join('')}</TR>
` ).join('')}</TABLE>`;

The content of the tbl variable is (for the provided sample data):

<TABLE>
<TR><TD>Errors</TD><TD>1472058000000</TD><TD>1472061600000</TD></TR>
<TR><TD>newview</TD><TD>359</TD><TD>338</TD></TR>
<TR><TD>oldview</TD><TD>169</TD><TD>184</TD></TR>
<TR><TD>noview</TD><TD>6</TD><TD>14</TD></TR>
<TR><TD>someview</TD><TD>0</TD><TD>1</TD></TR>
<TR><TD>TOTALS</TD><TD>534</TD><TD>537</TD></TR>
</TABLE>

var myData = [
      [{
        "timeBucket": 1472058000000,
        "errors": 534,
        "errorFree": 0,
        "business": 0,
        "errorRate": 1.0,
        "breakdown": [{
          "type": "newview",
          "count": 359,
          "errorRate": 1.0
        }, {
          "type": "oldview",
          "count": 169,
          "errorRate": 1.0
        }, {
          "type": "noview",
          "count": 6,
          "errorRate": 1.0
        }]
      }],
      [{
        "timeBucket": 1472061600000,
        "errors": 537,
        "errorFree": 0,
        "business": 0,
        "errorRate": 1.0,
        "breakdown": [{
          "type": "newview",
          "count": 338,
          "errorRate": 1.0
        }, {
          "type": "oldview",
          "count": 184,
          "errorRate": 1.0
        }, {
          "type": "noview",
          "count": 14,
          "errorRate": 1.0
        }, {
          "type": "someview",
          "count": 1,
          "errorRate": 1.0
        }]
      }]
    ];
var errorTypes = ["newview","oldview","noview","someview"];

// Create 2D array:
var arr = [
    ["Errors", ...myData.map( ([rec]) => rec.timeBucket )], 
    ...errorTypes.map( type => 
        [type,...myData.map( ([rec]) => 
            (rec.breakdown.find( err => err.type == type ) || {}).count || 0 )]), 
    ["TOTALS", ...myData.map( ([rec]) => rec.errors ) ]];

// Convert 2D array to HTML string:
var tbl = `<TABLE BORDER=1>
${arr.map( row => `<TR>${row.map( cell => `<TD>${cell}</TD>` ).join('')}</TR>
` ).join('')}</TABLE>`;

// Output in snippet:
document.body.innerHTML = tbl;
trincot
  • 317,000
  • 35
  • 244
  • 286
0

OK guys, this was ALL very helpful ( upvoted all responses ) because iteration of the data was what was confusing to me, but the answers were formatting the timebucket on the vertical and not the horizontal. I thought I could get away with only one pass, but it turns out I can't. What I got reminded of is the fact that JSON is sent out in a text string is, thusly, predictable in it's order. ( Thinking like a scripting developer, my block was thinking that JSON was like a hash and unpredictable).

So I posted the answer on my jsfiddle here: https://jsfiddle.net/wilkiejane/966sjb6k/

HTML

<div id="table"></div>

JS

errorTypes = ["newview","oldview","noview","someview"]
var myData = [
  [{
    "timeBucket": 1472058000000,
    "errors": 534,
    "errorFree": 0,
    "business": 0,
    "errorRate": 0.75,
    "breakdown": [{
      "type": "newview",
      "count": 359,
      "errorRate": 0.5
    }, {
      "type": "oldview",
      "count": 169,
      "errorRate": 1.0
    }, {
      "type": "noview",
      "count": 6,
      "errorRate": 1.0
    }]
  }],
  [{
    "timeBucket": 1472061600000,
    "errors": 537,
    "errorFree": 0,
    "business": 0,
    "errorRate":0.76,
    "breakdown": [{
      "type": "newview",
      "count": 338,
      "errorRate": 1.0
    }, {
      "type": "oldview",
      "count": 184,
      "errorRate": 1.0
    }, {
      "type": "noview",
      "count": 14,
      "errorRate": 1.0
    }, {
      "type": "someview",
      "count": 1,
      "errorRate": 1.0
    }]
  }]
];

function draw_tr(dataline){
      linedraw = "<tr><td>"+dataline+"</td></tr>"
        $('#table').append(linedraw);
      //$table.append( '<tr><td>' + 'result' +  i + '</td></tr>' );
}

errorTypes=["newview","oldview","noview","someview"];
var timebucket=["&nbsp"];
var totals=["Totals"];
var newview=["New View"];
var oldview=["Old View"];
var noview=["No View"];
var someview=["Some View"]; 
var errors=["Errors"];

myData.forEach(function(ele, idx) {
  timebucket.push(ele[0].timeBucket);
  timebucket.push(ele[0].timeBucket + "Error Rate")
  errors.push(parseFloat(ele[0].errors));
  errors.push(parseFloat(ele[0].errorRate));
  });

errorTypes.map( function (item) {
myData.forEach(function(ele, idx) {
  var count = ele[0].breakdown.filter(function(ele, idx) {
    return ele.type == item;
  })[0];
  count = (count === undefined) ? 0 : +count.count;
  var errorRate = ele[0].breakdown.filter(function(ele, idx) {
    return ele.type == item;
  })[0];
  errorRate = (errorRate === undefined) ? 0 : +errorRate.errorRate;
        switch (item){
            case "newview":
                        newview.push(count);
                  newview.push (errorRate);
                  break;
            case "oldview":
                    oldview.push(count);
                  oldview.push(errorRate);
                  break;
            case "noview":
                        noview.push(count);
                  noview.push(errorRate);
                  break;
            case "someview":
                        someview.push(count);
                  someview.push(errorRate)
                  break;
        }
  });  
});

$('#table').append("<TABLE BORDER=1>");

variable = "timebucket";

tableorder = ["timebucket", "newview", "oldview", "noview", "someview","errors"];
$.each( tableorder, function( i, l ){
  var dataline = eval(l).join('</td><td>');
    draw_tr(dataline);
});
$('#table').append("</TABLE>");

As usual, the SO community is one of the greatest resources and I can't thank you enough.

Jane Wilkie
  • 1,703
  • 3
  • 25
  • 49
-1

this might be one possible solution:

var result = myData.map(function(data){
  var res = [data[0].timeBucket];
  var total = 0;

  data[0].breakdown.forEach(function(bd){
    if(errorTypes.indexOf(bd.type) != -1){
      res[errorTypes.indexOf(bd.type) + 1] = bd.count;
      total += bd.count;
    }  
  });

  res[1+errorTypes.length] = total;

  return res;
});

result equals:

[
    [ 1472058000000, 359, 169, 6, undefined, 534 ],
    [ 1472061600000, 338, 184, 14, 1 , 537]
]

to format this result to the html table you are looking for:

var lines = ['Error', 'newview', 'oldview', 'noview', 'someview', 'TOTALS'];

table = '<TABLE>' + 
  lines.map(function(line, i){
    line = '<TR><TD>' + line + '</TD>'
    result.forEach(function(res){
      line += '<TD>' + (res[i] || 0) + '</TD>';
    })
    line += '</TR>'
    return line;
}).join("") + '</TABLE>'

and the fiddle: https://jsfiddle.net/vp4399au/

peerbolte
  • 1,169
  • 11
  • 19