Извлечь глубоко вложенные дочерние объекты по имени свойства с помощью lodash

У меня есть массивы глубоко вложенных объектов. Я хотел бы написать функцию для извлечения произвольных дочерних объектов из этих массивов. В некоторых случаях значения вложенных свойств являются значениями и объектами, в других случаях они являются массивами.

Примеры массивов ниже:

[{parent: {level1: {level2: 'data'}}}]

[{parent: {level1: [{level2: {...}}, {level2: {...}}, {level2: {...}}]}}]

[{parent: {level1: [{level2: {level3: 'data'}}, {level2: {..}}, {level2: {..}}]}}]

Вызов функции извлечения на таком массиве должен привести к массиву объектов, которые нас интересуют.

Примеры вызова функции и ее результатов для приведенных выше массивов примеров:

extractChildren(source, 'level2') = [{level2: 'data'}]

extractChildren(source, 'level2') = [{level2: {...}, level2: {...}, level2: {...}]

extractChildren(source, 'level3') = [{level3: 'data'}]

Есть ли сжатый способ достичь этого с помощью lodash или я должен использовать обычный JavaScript для итерации через свойства?

P.S. Подумайте об этом как эквивалент XPath select all nodes with the name "nodename"

Ответ 1

Надеюсь, это поможет:

'use strict';

let _ = require("lodash");
let source = [{parent: {level1: [{level2: {level3: 'data'}}, {level2: {}}, {level2: {}}]}}];

function extractChildren(source, specKey) {
    let results = [];
    let search = function(source, specKey) {
        _.forEach(source, function(item) {
            if (!!item[specKey]) {
                let obj = {};
                obj[specKey] = item[specKey];
                results.push(obj);
                return;
            }

            search(item, specKey);
        });
    };

    search(source, specKey);
    return results;
};

console.log(extractChildren(source, 'level3'));
// [ { level3: 'data' } ]

Ответ 2

Из этот вопрос:

Elegant:

function find_obj_by_name(obj, key) {
    if( !(obj instanceof Array) ) return [];

    if (key in obj)
        return [obj[key]];

    return _.flatten(_.map(obj, function(v) {
        return typeof v == "object" ? find_obj_by_name(v, key) : [];
    }), true);
}

Эффективность:

function find_obj_by_name(obj, key) {
    if( !(obj instanceof Array) ) return [];

    if (key in obj)
        return [obj[key]];

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