3

I've got some JSON data being returned from a REST call that I want to parse, add totals, then spit out arrays with new data. I've got the parsing, looping, and adding figured out, and can write the results on the page (see post: json sibling data), but I want to further break down the totals. Here's the JSON I'm starting with:

{"ResultSet":{

    "Result":[

    {
        "file_size":"722694",
        "desc":"description1",
        "format":"GIF"
    },

    {
        "file_size":"19754932",
        "desc":"description1",
        "format":"JPEG"
    },

    {
        "file_size":"778174",
        "desc":"description2",
        "format":"GIF"
    },

    {
        "file_size":"244569996",
        "desc":"description1",
        "format":"PNG"
    },

    {
        "file_size":"466918",
        "desc":"description2",
        "format":"TIFF"
    }

  ]

}}

I've got it returning the totals for each different "desc" (see answer: https://stackoverflow.com/a/13016615/1766026), but now I want to break it down one step further and show totals for each "desc" with each "format" so the new output would look like:

description1: 444MB (222MB TIFF, 111MB GIF, 111MB JPEG)

description2: 333MB (111MB PNG, 111MB TIFF, 111MB JPEG)

where not all returned items have the same kinds of file formats.

(yes, I know these numbers do not add up from the JSON - it's just an example)

I'm thinking this can be done by pushing the results to a new array(s) based on matching elements then iterating over that and spitting out to the page.

Maybe the new array(s)/object(s) would look like this?

{
    "desc":"description1",
    "TIFF":"222",
    "GIF:"111",
    "JPEG:"111"
},
{
    "desc":"description2",
    "PNG":"111",
    "TIFF:"111",
    "JPEG":"111"
}

I just saw this: How do I create JavaScript array (JSON format) dynamically? I guess that would be one place to start?

(please pardon possible improper terminology - I do mostly front-end work and this kind of stuff is pretty new to me - polite constructive criticisms gladly accepted)

Community
  • 1
  • 1
mflorida
  • 43
  • 1
  • 7
  • I'd point out that while your example is relatively trivial, you're edging towards doing the processing on the client as opposed to the server. There could be good reasons for this but if it's possible to get the server to return the aggregate data, it may save you some pain in the long-run. This is the sort of thing SQL is designed for and while it can be done in other languages, you often end up with large complex libraries for all your aggregation scenarios if you want it to be flexible. – Basic Oct 23 '12 at 23:46
  • This is for a web app that uses its own REST API to pull info like this. We do most of the page display using javascript/AJAX/JSON. All of this info is available via REST so we like to use that when possible. If this ends up being too slow we may well dive into the server-side code to spit out some HTML. Thanks for your input. – mflorida Oct 24 '12 at 00:13
  • I understand completely - and do very much myself. My UI guys often end up asking for a `/StatsBy/DocType`, `/StatsBy/Author`, etc... for that very reason. Anyway, welcome to SO. Hope to see you around – Basic Oct 24 '12 at 00:24

1 Answers1

1

Yes. Iterate the array and build your objects from it.

var arr = parsedObj.ResultSet.Result;

var byDesc = {}; // an object as a key-value-map
for (var i=0; i<arr.length; i++) {
    var desc = arr[i].desc,
        format = arr[i].format;
    if (! (desc in byDesc))
        byDesc[desc] = {};
    if (! (format in byDesc[desc]))
        byDesc[desc][format] = 0;
    byDesc[desc][format] += (+arr[i].file_size); // parseInt
}

now we've got an object with filesizes by format and description:

{"description1":{"GIF":722694,"JPEG":19754932,"PNG":244569996},"description2":{"GIF":778174,"TIFF":466918}}

to get the desired output, we just enumerate this object:

var output = [];
for (var desc in byDesc) {
    var total = 0,
        formats = [];
    for (var format in byDesc[desc]) {
        formats.push(Math.round(byDesc[desc][format]/1000)+"MB "+format);
        total += byDesc[desc][format];
    }
    output.push(desc+": "+Math.round(total/1000)+"MB ("+formats.join(", ")+")");
}
return output.join("\n");

and we get

description1: 265048MB (723MB GIF, 19755MB JPEG, 244570MB PNG)
description2: 1245MB (778MB GIF, 467MB TIFF)
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I got the first chunk of code working. First as-is, then I tweaked it to work in an existing jQuery $.each loop that is doing some other stuff. Shows up fine doing `console.debug(byDesc);`. But how do I access the top-level for output (**"description1"** etc.)? I can't get the output like you have shown. It doesn't do anything as-is and I'm not sure how to use the `return` to render the output (pardon my raw javascript newbie-isms, I mostly do front-end work with jQuery). I'd like to render with jQuery's `.append()` function if possible. Thanks! – mflorida Oct 24 '12 at 01:22
  • Here's the output I get - and only one line: **undefined: 3.738 GB (2.082 GB DICOM, 51.65 MB GIF, 1.605 GB NIFTI, 178 KB )** using this code: `$('body').append(output.join("\n"));`. How can the top-level "desc" name be accessed? – mflorida Oct 24 '12 at 01:39