Найти свойство по имени в глубоком объекте

У меня есть коллекция HUGE, и я ищу свойство по ключевому слову внутри коллекции. Что такое надежный способ получить список ссылок или полные пути ко всем объектам, содержащим этот ключ/индекс? Я использую jQuery и lodash, если это помогает, и вы можете забыть о бесконечной рекурсии указателя, это чистый ответ JSON.

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d"); 
// [o.c]

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e");
// [o.c.d]

fn({ 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');
// [o.cc,o.cc.dd]

fwiw lodash имеет функцию _.find, которая найдет вложенные объекты, которые являются двумя гнездами глубоко, но после этого они, похоже, не сработают. (например, http://codepen.io/anon/pen/bnqyh)

Ответ 1

Это должно сделать это:

function fn(obj, key) {
    if (_.has(obj, key)) // or just (key in obj)
        return [obj];
    // elegant:
    return _.flatten(_.map(obj, function(v) {
        return typeof v == "object" ? fn(v, key) : [];
    }), true);

    // or efficient:
    var res = [];
    _.forEach(obj, function(v) {
        if (typeof v == "object" && (v = fn(v, key)).length)
            res.push.apply(res, v);
    });
    return res;
}

Ответ 2

чистое решение JavaScript будет выглядеть следующим образом:

function findNested(obj, key, memo) {
  var i,
      proto = Object.prototype,
      ts = proto.toString,
      hasOwn = proto.hasOwnProperty.bind(obj);

  if ('[object Array]' !== ts.call(memo)) memo = [];

  for (i in obj) {
    if (hasOwn(i)) {
      if (i === key) {
        memo.push(obj[i]);
      } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
        findNested(obj[i], key, memo);
      }
    }
  }

  return memo;
}

здесь, как вы будете использовать эту функцию:

findNested({'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');

и результат будет следующим:

[{x: 9}, {y: 9}]

Ответ 3

это приведет к глубокому поиску массива объектов (сена) для значения (игла), а затем возвращает массив с результатами...

search = function(hay, needle, accumulator) {
  var accumulator = accumulator || [];
  if (typeof hay == 'object') {
    for (var i in hay) {
      search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1;
    }
  }
  return new RegExp(needle).test(hay) || accumulator;
}

Ответ 4

Что-то вроде этого будет работать, преобразуя его в объект и рекурсивный.

function find(jsonStr, searchkey) {
    var jsObj = JSON.parse(jsonStr);
    var set = [];
    function fn(obj, key, path) {
        for (var prop in obj) {
            if (prop === key) {
                set.push(path + "." + prop);
            }
            if (obj[prop]) {
                fn(obj[prop], key, path + "." + prop);
            }
        }
        return set;
    }
    fn(jsObj, searchkey, "o");
}

Fiddle: jsfiddle

Ответ 5

Array.prototype.findpath = function(item,path) {
  return this.find(function(f){return item==eval('f.'+path)});
}

Ответ 6

Вот как я это сделал:

function _find( obj, field, results )
{
    var tokens = field.split( '.' );

    // if this is an array, recursively call for each row in the array
    if( obj instanceof Array )
    {
        obj.forEach( function( row )
        {
            _find( row, field, results );
        } );
    }
    else
    {
        // if obj contains the field
        if( obj[ tokens[ 0 ] ] !== undefined )
        {
            // if we're at the end of the dot path
            if( tokens.length === 1 )
            {
                results.push( obj[ tokens[ 0 ] ] );
            }
            else
            {
                // keep going down the dot path
                _find( obj[ tokens[ 0 ] ], field.substr( field.indexOf( '.' ) + 1 ), results );
            }
        }
    }
}

Тестирование:

var obj = {
    document: {
        payload: {
            items:[
                {field1: 123},
                {field1: 456}
                ]
        }
    }
};
var results = [];

_find(obj.document,'payload.items.field1', results);
console.log(results);

Выходы

[ 123, 456 ]