Moustafa Elkady
Moustafa Elkady

Reputation: 670

object dynamic filtering with nested array of objects using javascript

i have this data sample,

{
    "section": [
        {
            "id": 1,
            "name" : "dogs"
        },
        {
            "id": 2,
            "name" : "cats"
        }
    ],
    "price" : [
        {

            "name" : "monthly",
            "price": {
                "amount": 10
            }
        }
    ],
    "specs": {
        "color" : {
            "name" : "green"
        }
    }
}

i want to pick some properties from that object, like that

const obj = pick(obj,["section.id","price.price"])

it should gives an object:

{
    "section": [
        {
            "id": 1,
        },
        {
            "id": 2,
        }
    ],
    "price" : [
        {
            "price": {
                "amount": 10
            }
        }
    ],
}

i tried lodash.pick() and didn't understand the array of object case, it understand it if i used this syntax "section[0].name" and i want it generic, like "section.name"

Upvotes: 2

Views: 546

Answers (2)

Akrion
Akrion

Reputation: 18515

If you re already using lodash I do not see a reason to write your own _.pick but that is up to you. Here is how you can do this with lodash in one line or in few with chaining:

let obj = { "section": [{ "id": 1, "name": "dogs" }, { "id": 2, "name": "cats" } ], "price": [{ "name": "monthly", "price": { "amount": 10 } }], "specs": { "color": { "name": "green" } } }

let resultA = _.mapValues(_.omit(obj, ['specs']), a => _.map(a, o => _.pick(o, ['id', 'price'])))

// OR cleaner and more readable with _.chain

let resultB = _(obj)
  .omit(['specs'])
  .mapValues(a => _.map(a, o => _.pick(o, ['id', 'price'])))
  .value()

console.log(resultA)
console.log(resultB)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

The idea is to _.mapValues through the objects and map over the arrays to pick what you need. In this case 'id' and 'price'.

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386654

You could take a custom pick function which take the wanted properties and takes all nested arrays without being part of the pathes.

function pick(object, keys) {
    if (Array.isArray(object)) return object.map(o => pick(o, keys));
    var pathes = keys.reduce((r, key) => {
        var [k, ...rest] = key.split('.'),
            temp = r.find(([l]) => k === l),
            left = rest.join('.');

        if (!(k in object)) return r;
        if (!temp) r.push(temp = [k, []]);
        if (left) temp[1].push(left);
        return r;
    }, []);
    return Object.assign({}, ...pathes.map(([k, rest]) => ({ [k]: rest.length
        ? pick(object[k], rest)
        : object[k]
    })));
}

var data = { section: [{ id: 1, name: "dogs" }, { id: 2, name: "cats" }], price: [{ name: "monthly", price: { amount: 10 } }], specs: { color: { name: "green" } } },
    result = pick(data, ["section.id", "price.price"]);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Related Questions