0

I am working on a solution where I need to search for an element in a deeply nested JSON by its id. I have been advised to use underscore.js which I am pretty new to.

After reading the documentation http://underscorejs.org/#find , I tried to implement the solution using find, filter and findWhere.

Here is what I tried using find :

 var test = {
    "menuInputRequestId": 1,
    "catalog":[
      {
        "uid": 1,
        "name": "Pizza",
        "desc": "Italian cuisine",
        "products": [
          {
            "uid": 3,
            "name": "Devilled chicken",
            "desc": "chicken pizza",
            "prices":[
              {
                "uid": 7,
                "name": "regular",
                "price": "$10"
              },
              {
                "uid": 8,
                "name": "large",
                "price": "$12"
              }
            ]
          }
        ]
      },
      {
        "uid": 2,
        "name": "Pasta",
        "desc": "Italian cuisine pasta",
        "products": [
          {
            "uid": 4,
            "name": "Lasagne",
            "desc": "chicken lasage",
            "prices":[
              {
                "uid": 9,
                "name": "small",
                "price": "$10"
              },
              {
                "uid": 10,
                "name": "large",
                "price": "$15"
              }
            ]
          },
          {
            "uid": 5,
            "name": "Pasta",
            "desc": "chicken pasta",
            "prices":[
              {
                "uid": 11,
                "name": "small",
                "price": "$8"
              },
              {
                "uid": 12,
                "name": "large",
                "price": "$12"
              }
            ]
          }
        ]
      }
    ]
  };

var x = _.find(test, function (item) {
    return item.catalog && item.catalog.uid == 1;
});

And a Fiddle http://jsfiddle.net/8hmz0760/

The issue I faced is that these functions check the top level of the structure and not the nested properties thus returning undefined. I tried to use item.catalog && item.catalog.uid == 1; logic as suggested in a similar question Underscore.js - filtering in a nested Json but failed.

How can I find an item by value by searching the whole deeply nested structure?

EDIT:

The following code is the latest i tried. The issue in that is that it directly traverses to prices nested object and tries to find the value. But my requirement is to search for the value in all the layers of the JSON.

var x = _.filter(test, function(evt) {
    return _.any(evt.items, function(itm){
        return _.any(itm.outcomes, function(prc) {
            return prc.uid === 1 ;
        });
    });
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Hasitha Shan
  • 2,900
  • 6
  • 42
  • 83
  • `catalog` is an array you cannot access the objects inside the array without using an index ie `item.catalog[0].uid` so you would have to loop over catalog and do a check for uid. – Patrick Evans May 07 '15 at 03:54
  • @PatrickEvans Woah. you are right, but I tried your suggestion on the fiddle but it still giving me `undefined`. ideally it should check all the uid's in each nested array. – Hasitha Shan May 07 '15 at 04:09
  • JSON is a *textual notation* for data exchange. [(More here.)](http://stackoverflow.com/a/2904181/157247) If you're dealing with JavaScript source code, and not dealing with a *string*, you're not dealing with JSON. – T.J. Crowder Aug 21 '17 at 12:22

2 Answers2

2

I dont use underscore.js but you can use this instead

function isArray(what) {
return Object.prototype.toString.call(what) === '[object Array]';
}

function find(json,key,value){
var result = [];
for (var property in json)
{
    //console.log(property);
    if (json.hasOwnProperty(property)) {
        if( property == key && json[property] == value)
        {
            result.push(json);
        }
        if( isArray(json[property]))
        {
            for(var child in json[property])
            {
                //console.log(json[property][child]);
                var res = find(json[property][child],key,value);
                if(res.length >= 1 ){
                    result.push(res);}
            }
        }
    }
}
return result;
}

console.log(find(test,"uid",4));
kwangsa
  • 1,701
  • 12
  • 16
  • Hi, thanks you so much fro the answer.. this solution works perfectly. this will be my solution if I fail to find an underscore js alternative. +1 Thanks a bunch :) – Hasitha Shan May 07 '15 at 05:18
2

Here's a solution which creates an object where the keys are the uids:

var catalogues = test.catalog;
var products = _.flatten(_.pluck(catalogues, 'products'));
var prices = _.flatten(_.pluck(products, 'prices'));

var ids = _.reduce(catalogues.concat(products,prices), function(memo, value){
  memo[value.uid] = value;
  return memo;
}, {});

var itemWithUid2 = ids[2]
var itemWithUid12 = ids[12]
Gruff Bunny
  • 27,738
  • 10
  • 72
  • 59