Getting multiple keys' values from nested object in JSON (w/out jQuery) I'd like to ask if either my JSON data is ill-conceived and whether how I solved it is particularly inefficient/plain stupid/typical.

Given the following JSON data:

{
    "User01": {
        "dates &amp; times": {
            "date 01": "150",
            "date 02": "165",
            "date 03": "180"
        }
    },

    "User02": {
        "dates &amp; times": {
            "date 01": "150",
            "date 02": "165",
            "date 03": "180"
        }
    },

    "User03": {
        "dates &amp; times": {
            "date 01": "150",
            "date 02": "165",
            "date 03": "180"
        }
    }
}


... and wanting to retrieve the dates &amp; times data so it can be rendered, e.g.:

Date 01: Time 01
Date 02: Time 02
Date 03: Time 03


... and which I've achieved thusly:

for (var key in myObj){
    if (key == selUser){
        for (var date in myObj[key]["dates &amp; times"]){
            console.log("Date: " + date + "; " + "weight: " + myObj[key]["dates &amp; times"][date]);
            var dtTag = "&lt;dt class=\"date\"&gt;&lt;span&gt;Date: &lt;/span&gt;" + date + " &lt;/dt&gt;";
            var ddTag = "&lt;dd class=\"value\"&gt;&lt;span&gt;Time: &lt;/span&gt;" + myObj[key]["dates &amp; times"][date] + "&lt;/dd&gt;";
            output.innerHTML += dtTag;
            output.innerHTML += ddTag;
        }
    } // if 
} // loop


So, as to the json data: assuming that there could be hundreds of date &amp; time entries, is this even a legit usage of json or should this kind of data be better formatted using arrays, e.g.:

{ "dates &amp; times":
    {
        "dates": [ "date01", "date02", "date03" ],
        "times": [ "150", "165", "180" ]
    }
}


And in such a case where I had no control of the JSON data, how could I improve on my solution to iterate for selected user and iterate again through nested object's data?

By the way, this is in context of studying JavaScript, not jQuery or any other library/framework.
{ "dates &amp; times":
    {
        "dates": [ "date01", "date02", "date03" ],
        "times": [ "150", "165", "180" ]
    }
}



No, don't do that. You take an explicit relationship in one data structure and make it implicit between two data structures. Instead, do:

{ "dates &amp; times": [
    { "date": "2014-08-24", "time": "150" },
    { "date": "2014-08-24", "time": "165" },
    { "date": "2014-08-24", "time": "180" },
] }


Now the relationship is explicit, and you can iterate over the array more simply and safely than iterating over the keys. (Safely because, if a property is added to Object.prototype, it will show up as a key.)


for (var key in myObj){
    if (key == selUser){
        for (var date in myObj[key]["dates &amp; times"]){
            console.log("Date: " + date + "; " + "weight: " + myObj[key]["dates &amp; times"][date]);
            var dtTag = "&lt;dt class=\"date\"&gt;&lt;span&gt;Date: &lt;/span&gt;" + date + " &lt;/dt&gt;";
            var ddTag = "&lt;dd class=\"value\"&gt;&lt;span&gt;Time: &lt;/span&gt;" + myObj[key]["dates &amp; times"][date] + "&lt;/dd&gt;";
            output.innerHTML += dtTag;
            output.innerHTML += ddTag;
        }
    } // if 
} // loop



This has a bit more going on than is totally necessary. The outer loop is superfluous, since we only actually do something for one key. The inner loop changes with our new data structure. Also, we can do a bit of reorganization to help performance a bit. We will also change the if statement into a guard clause to clarify the code path.

// Is this key in the object, and does it have the right property?
if(!myObj[selUser] || !myObj[selUser]["dates &amp; times"]) { // return, throw error, whatever }

output.innerHTML += myObj[selUser]["dates &amp; times"].map(function(el){
    console.log("Date: " + el.date + "; Time: " + el.time);
    var dtTag = "&lt;dt class=\"date\"&gt;&lt;span&gt;Date: &lt;/span&gt;" + el.date + "&lt;/dt&gt;";
    var ddTag = "&lt;dd class=\"value\"&gt;&lt;span&gt;Time: &lt;/span&gt;" + el.time + "&lt;/dd&gt;";

    return dtTag + ddTag;
}).join("");


This relies on a newer ES5 feature, so polyfill or replace with equivalent loops if you need to support older browsers (see below). Also, this code does not exactly give the output you specified, FYI.



Without Array#map:

// Is this key in the object, and does it have the right property?
if(!myObj[selUser] || !myObj[selUser]["dates &amp; times"]) { // return, throw error, whatever }

var i, el, dtTag, ddTag;

var listItems = [];
var datesAndTimes = myObj[selUser]["dates &amp; times"];
var datesAndTimesLength = datesAndTimes.length;

for(i = 0; i &lt; datesAndTimesLength; i++) {
    el = datesAndTimes[i];
    console.log("Date: " + el.date + "; Time: " + el.time);
    dtTag = "&lt;dt class=\"date\"&gt;&lt;span&gt;Date: &lt;/span&gt;" + el.date + "&lt;/dt&gt;";
    ddTag = "&lt;dd class=\"value\"&gt;&lt;span&gt;Time: &lt;/span&gt;" + el.time + "&lt;/dd&gt;";

    listItems.push(dtTag + ddTag);
}

output.innerHTML += listItems.join("");