1

I have a complex object with nested values. Values could be strings, arrays, arrays of objects or null objects. Something like this:

{
foo:'a',
bar:'b',
otherthings : [{yep:'0',yuk:'yoyo0'},{yep:'1',yuk:'yoyo1'}],
foobar : 'yup',
value: null
}

What is the fastest way to check if a value (e.g. yoyo1) exists somewhere in the object? Is there a Javascript built-in function?

floatingpurr
  • 7,749
  • 9
  • 46
  • 106
  • possible duplicate of [Javascript find json value](http://stackoverflow.com/questions/19253753/javascript-find-json-value) – Marcos Pérez Gude Sep 14 '15 at 15:35
  • 2
    _Is there a Javascript built-in function?_ No, you have to implement it yourself. Recursion is your friend. – hindmost Sep 14 '15 at 15:37
  • 1
    nope, javascript has not built-in function, but you can use simple `for...in` loop and check all manually – Grundy Sep 14 '15 at 15:37
  • you can either iterate over each object key/value or if you just care about knowing if the value is there you can use JSON.stringify to convert the object to text and search for the ":'value'" you can use regex on the string – Saar Sep 14 '15 at 15:38
  • I think that JSON.stringify + RegEx is more efficient than classic recursion, isn't it? – floatingpurr Sep 14 '15 at 15:40
  • @MarcosPérezGude I check that post but my problem is how to explore the object in deep in efficient way and dealing with null values – floatingpurr Sep 14 '15 at 15:42
  • 1
    JSON.stringify + RegEx makes internal recursions, so is the same performance. There´s an answer below that makes with `indexOf` that needs to iterate through all the string. Performance will be the same or almost very similar. The best you can do is what you think that's more readable and simple to write. – Marcos Pérez Gude Sep 14 '15 at 16:14

4 Answers4

4

Some short iteration:

var data = {
    foo: 'a',
    bar: 'b',
    otherthings: [{ yep: '0', yuk: 'yoyo0' }, { yep: '1', yuk: 'yoyo1' }],
    foobar: 'yup',
    value: null
};

function findInObject(o, f) {
    return Object.keys(o).some(function (a) {
        if (Array.isArray(o[a]) || typeof o[a] === 'object' && o[a] !== null) {
            return findInObject(o[a], f);
        } 
        return o[a] === f;
    });
}

document.write(findInObject(data, 'yoyo1') + '<br>');
document.write(findInObject(data, 'yoyo2') + '<br>');
document.write(findInObject(data, null) + '<br>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

Regex Solution

var myObject = {
    foo: 'a',
    bar: 'b',
    otherthings: [{
        yep: '0',
        yuk: 'yoyo0'
    }, {
        yep: '1',
        yuk: 'yoyo1'
    }],
    foobar: 'yup',
    value: null
};

var myStringObject = JSON.stringify(myObject);
var matches = myStringObject.match('yep'); //replace yep with your search query

demo

Johan
  • 8,068
  • 1
  • 33
  • 46
  • 1
    This will also match if the json has the attribute yep, not necessarily the value 'yep'. – RainingChain Sep 14 '15 at 15:44
  • and I completely agree with you, thus the query needs to be right – Johan Sep 14 '15 at 15:45
  • Ok sounds good. In that way I can also search for a substring like `'y'` or `'yo'`. The unique problem I see, is when I search for a substring like `'nu'`,`'ul'` or `'null'` because I include also `null` match from stringified object – floatingpurr Sep 14 '15 at 15:56
1
var jsonStr = JSON.stringify(myJSON);
return jsonStr.indexOf(':"yolo1"') !== -1;

This only works if you want to know if it exists (not where it is). It may also not be the most performant.

RainingChain
  • 7,397
  • 10
  • 36
  • 68
1

Another solution:

 function findInObject(obj, comparedObj){
     return Object.keys(obj).some(function(key){
         var value = obj[key];

         if (!value) {
           return false;
         }

         if (typeof value === "string") {
            return value === comparedObj;
         }

         if (value instanceof Array) {
            return value.some(function(e){ 
                return (typeof value === "string" && e === comparedObj) || 
                       findInObject(e, comparedObj);
            });
         }

         return findInObject(value, comparedObj);
    });  
}
Sagi
  • 8,972
  • 3
  • 33
  • 41