27

Let say I have json data like

data = {"id":1,
        "name":"abc",
        "address": {"streetName":"cde",
                    "streetId":2
                    }
        }

Now I am getting fields to be accessed from this json data like : fields = ["id", "name", "address.streetName"]

How could I access third field (address.streetName) from given json data in most efficient way? data.fields[2] doesn't work

One possibility is I construct data[address][streetName] string using a for loop and do eval of that but is there any efficient way of doing this?

Salman A
  • 262,204
  • 82
  • 430
  • 521
Abhinav SInghvi
  • 391
  • 1
  • 4
  • 13

8 Answers8

47

To be honest, I can't understand your problem. JSON is already structured out, why do you need to change the structure?

In you case, I would access it as follows:

data.address.streetName;

If, by any chance, what you want is to traverse the data, you would need:

function traverse_it(obj){
    for(var prop in obj){
        if(typeof obj[prop]=='object'){
            // object
            traverse_it(obj[prop[i]]);
        }else{
            // something else
            alert('The value of '+prop+' is '+obj[prop]+'.');
        }
    }
}

traverse_it(data);

Update

After reading below, what this user needs seems more obvious. Given property names as a string, s/he wants to access the object.

function findProp(obj, prop, defval){
    if (typeof defval == 'undefined') defval = null;
    prop = prop.split('.');
    for (var i = 0; i < prop.length; i++) {
        if(typeof obj[prop[i]] == 'undefined')
            return defval;
        obj = obj[prop[i]];
    }
    return obj;
}

var data = {"id":1,"name":"abc","address":{"streetName":"cde","streetId":2}};
var props = 'address.streetName';
alert('The value of ' + props + ' is ' + findProp(data, props));
Christian
  • 27,509
  • 17
  • 111
  • 155
  • 1
    +1 I think you have got `data.address.streetName` right, that is what he is looking for probably though his question isn't clear. – Sarfraz Feb 27 '12 at 10:27
  • Hmm I will explain it again: address.streetName is a variable coming to me. I have data in json format with me. The situation is like I have data in JSON format and someone is passing "address.streetName" to me and the problem is how should I access value for this key from data – Abhinav SInghvi Feb 27 '12 at 10:28
  • Yes I thinks its the most efficient solution of this problem. Thanks. – Abhinav SInghvi Feb 27 '12 at 10:51
  • Be sure to mark the answer that helped you out as the 'right answer'. – Christian Feb 27 '12 at 11:21
  • Line 5 should be `obj = obj[prop[i]]`. Also remember to try-catch errors if property string cannot be found in object. Otherwise an excellent answer. +1 – Martin Hallén Jul 30 '14 at 12:19
  • @Christian Could you please give me some solution for this https://stackoverflow.com/questions/52039222/how-to-implement-hierarchical-multilevel-datatable-in-javascript?noredirect=1#comment91031196_52039222 – Varun Sharma Aug 29 '18 at 08:43
24

If you use lodash(a very popular utility library), you can use _.get().

e.g.

var data = {
  "id":1,
  "name": "abc",
  "address": {
    "streetName": "cde",
    "streetId":2
  }
}
_.get(data, 'address.streetName');
// 'cde'
_.get(data, ['address', 'streetName']);
// 'cde'

If it involves an array, you can use string path like 'address[0].streetName' as well.

e.g.

var data = {
  "id":1,
  "name": "abc",
  "addresses": [
    {
      "streetName": "cde",
      "streetId": 2
    },
    {
      "streetName": "xyz",
      "streetId": 102
    },
  ]
}
_.get(data, 'addresses[0].streetName');
// cde
_.get(data, [address, 1, streetName]);
// xyz

Internally, it uses toPath() function to convert string path (e.g. address.streetName) into an array (e.g. ['address', 'streetName']), and then uses a function to access the data at the given path within the object.

Other similar utility functions include _.set() and _.has(). Check them out.

Brian Park
  • 2,557
  • 22
  • 21
15

Long story short, you can use the array notation object[property] instead of object.property; this is specially useful when the keys contains special characters:

var data = {
    "id": 1,
    "name": "abc",
    "address": {
        "streetName": "cde",
        "streetId": 2
    }
}

data.address.streetName;              // (1) dot notation
data["address"]["streetName"];        // (2) array notation
var field = "streetName";
data["address"][field];               // (3) variable inside array notation
var fields = "address.streetName".split(".");
data[fields[0]][fields[1]];           // (4) specific to your question

You can use the typeof operator to check whether a property exists or not before using it:

typeof data["address"]["streetName"]; // returns "string"
typeof data["address"]["foobarblah"]; // returns "undefined"
Christian
  • 27,509
  • 17
  • 111
  • 155
Salman A
  • 262,204
  • 82
  • 430
  • 521
2

I did it like this:

var data = {
    "id": 1,
    "name": "abc",
    "addresses": [{
        "streetName": "cde",
        "streetId": 2
    }, {
        "streetName": "xyz",
        "streetId": 102
    }, ]
}

data2 = data["addresses"]
for (let i in data2) {
    console.log(data2[i]["streetName"]);
}
2

Your data variable doesn't have a fields property, and that's why data.fields[2] doesn't work. I think what you're trying to do there is data[fields[2]], which would work for a simple object, but you can't index into a complex object like that.

Greg B
  • 14,597
  • 18
  • 87
  • 141
  • yes correct so is there any efficient way to access nested data compare to following : col = "address.streetName" //key exp = "x" // data; col = col.split(".") for(var i=0; i – Abhinav SInghvi Feb 27 '12 at 10:21
2

you can access it this way data.address.streetName

Joseph Le Brech
  • 6,541
  • 11
  • 49
  • 84
1

This is a function I use to find data in nested objects:

Object.prototype.find = function() {
  try {
    return Array.prototype.slice.call(arguments).reduce(function(acc, key) {
      return acc[key]
    }, this)
  }
  catch(e) {
    return 
  }
}

Data structure:

data = {
  "id":1,
  "name":"abc",
  "address": {
    "streetName":"cde",
    "streetId":2
  }
}

Function call:

data.find("address","streetName")

Returns:

"cde"
1

JavaScript:

function getProperty(json, path) {
    var tokens = path.split(".");
    var obj = json;
    for (var i = 0; i < tokens.length; i++) {
        obj = obj[tokens[i]];
    }
    return obj;
}

var data = {
    id: 1,
    name: "abc",
    address: {
        streetName: "cde",
        streetId: 2
    }
};

var fields = ["id", "name", "address.streetName"];

for (var i = 0; i < fields.length; i++) {
    var value = getProperty(data, fields[i]);
    console.log(fields[i] + "=" + value);
}

Output:

id=1
name=abc
address.streetName=cde
Michael Righi
  • 1,333
  • 9
  • 11
  • Thanks Michael ..this is what I am doing..just wondering if there could be more efficient way of doing that.. – Abhinav SInghvi Feb 27 '12 at 10:35
  • Just realized I was doing unnecessary eval after constructing data["address"]["streetName"] using for loop. I think your's answer is most efficient. Thanks a lot. – Abhinav SInghvi Feb 27 '12 at 10:45