tinyplanet00 tinyplanet00 - 7 months ago 67
Javascript Question

Using underscore.js to find values in deeply nested JSON

I'm pretty new to Javascript, and I just learned about underscore.js. I have a deeply nested JSON object, and I need to use underscore to find key/value pairs, which I will then use to populate various HTML tables. If the structure was more shallow, using something like _.pluck would be easy, but I just don't know how to traverse past the first couple of nesting levels (i.e. surveyGDB, table, tablenames). The JSON object comes from an XML that is comprised of multiple nesting structures (mashed up from different database tables).

var JSONData =
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [
{
"#text": "SurveyInfo\n ",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
},
{
"#text": "QaQcPoints\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
},
{
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
},
{
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
},
{
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}
]
},
{
"#text": "QaQcPolygons\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}
]
}
]
}
}
}


For instance, I wanted all of the values for 'Code' in the 'QaQCPoints' table, so I tried:

var codes = _.flatten(_.pluck(JSONData.surveyGDB.table.tablename[1].record[0], "Code" ));
console.log(codes);


In the console, this returns an array with a length of 5, but with blank values.
What am I doing wrong?

I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.

nem nem
Answer

If I understood you correctly, you want to always search the record array within JSONData.surveyGDB.table.tablename array for some queries. This means you need to find the record based on some parameter and return something from the found record.

Do note that the record property is sometimes an array and sometimes an object (for table SurveyInfo) in your example so I'll assume you need to take this into account. You can make a small function to extract data and handle both objects and arrays:

function extract(record, property) {
  if (Array.isArray(record)) { 
    return _.pluck(record, property);
  } else {
    return record[property];
  }
}

Usage example:

I wanted all of the values for 'Code' in the 'QaQCPoints' table. I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.

To achieve this you first find a record using _.find, and then extract Code values from it using the method above:

var table = JSONData.surveyGDB.table.tablename;

// find an item that has `#text` property equal to `QaQcPoints`
var item = _.find(table, function(r) {
  return r['#text'] === 'QaQcPoints';
});

// extract codes from the found item's record property
var code = extract(item.record, 'Code');
// output ["tp", "tb", "to", "bl", "bf"]

Running sample:

var JSONData = {
  "surveyGDB": {
    "filename": "..\\Topo\\SurveyGeoDatabase.gdb",
    "table": {
      "tablename": [{
        "#text": "SurveyInfo",
        "record": {
          "OBJECTID": "1",
          "SiteID": "CBW05583-345970",
          "Watershed": "John Day",
          "VisitType": "Initial visit",
          "SurveyInstrument": "Total Station",
          "ImportDate": "2015-07-22T09:08:42",
          "StreamName": "Duncan Creek",
          "InstrumentModel": "TopCon Magnet v2.5.1",
          "FieldSeason": "2015"
        }
      }, {
        "#text": "QaQcPoints",
        "record": [{
          "OBJECTID": "1",
          "TIMESTAMP": "2015-07-22T09:18:43",
          "Code": "tp",
          "Count": "357"
        }, {
          "OBJECTID": "2",
          "TIMESTAMP": "2015-07-22T09:18:43",
          "Code": "tb",
          "Count": "92"
        }, {
          "OBJECTID": "3",
          "TIMESTAMP": "2015-07-22T09:18:43",
          "Code": "to",
          "Count": "8"
        }, {
          "OBJECTID": "4",
          "TIMESTAMP": "2015-07-22T09:18:43",
          "Code": "bl",
          "Count": "279"
        }, {
          "OBJECTID": "5",
          "TIMESTAMP": "2015-07-22T09:18:43",
          "Code": "bf",
          "Count": "18"
        }]
      }, {
        "#text": "QaQcPolygons",
        "record": [{
          "OBJECTID": "1",
          "TIMESTAMP": "2015-07-22T09:43:08",
          "SurveyExtentCount": "",
          "WaterExtentCount": "",
          "ChannelUnitsCount": "",
          "ChannelUnitsUnique": ""
        }, {
          "OBJECTID": "2",
          "TIMESTAMP": "2015-07-22T13:35:15",
          "SurveyExtentCount": "1",
          "WaterExtentCount": "1",
          "ChannelUnitsCount": "21",
          "ChannelUnitsUnique": "21"
        }]
      }]
    }
  }
}

function extract(record, property) {
  if (Array.isArray(record)) {
   return _.pluck(record, property);
  } else {
    return record[property];
  }
}

var table = JSONData.surveyGDB.table.tablename;

var item = _.find(table, function(r) {
  return r['#text'] === 'QaQcPoints';
});

console.dir(item);

var code = extract(item.record, 'Code');

console.log(code);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>