Apply a filter on a multilevel object based on a different object

Viewed 62

I have an array with multilevel objects, such as:

list= [ {  
           type: { name: 'dog', size:'medium'},
           entity: { name: 'Tobby',  age: '7'},
         },
         {  
           type: { name: 'cat', size:'small'},
           entity: { name: 'Garfield',  age: '7'},
         }
    ]

And I have a defined filter such as:

filter={
         type: { name:'dog'}}

I need to define a function such that I can call

let filtered = list.thisMagicFilter(filter)

that will filter accordingly on my list (in the given example, returning only the first element.

Logically, if the filter is {entity:{age:'7'}}, then both results should be returned.

I've broken my head trying to do this in a functional programming with a list.filter(), but it's just too complex for me: I'm struggling on the fact that it's a 2 level validation.

Can I get some hint of how to tackle this problem?

Thank you in advance!

2 Answers

You could take a recursive filter for nested objects and hand ocer the part filer and the part data object until no more nested objects.

const
    list = [{ type: { name: 'dog', size: 'medium' }, entity: { name: 'Tobby', age: '7' } }, { type: { name: 'cat', size: 'small' }, entity: { name: 'Garfield', age: '7' } }],
    filter = { type: { name: 'dog' } },
    filterBy = f => o => Object
        .entries(f)
        .every(([k, v]) => typeof v === 'object'
            ? filterBy(v)(o[k])
            : o[k] === v
        ),
    result = list.filter(filterBy(filter));

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

Try this:

const _matchesFilter = (e, conditions = []) =>
  conditions.every(([prop, condition]) => {
    const subConditions = Object.entries(condition);
    return subConditions.every(([ subProp, subCondition ]) =>
      e[prop]?.[subProp] === subCondition
    );
  });

const thisMagicFilter = (list = [], filter = {}) => {
  const conditions = Object.entries(filter);
  return list.filter(e => _matchesFilter(e, conditions));
}

const list= [ 
  { type: { name: 'dog', size:'medium'}, entity: { name: 'Tobby',  age: '7'} },
  { type: { name: 'cat', size:'small'}, entity: { name: 'Garfield',  age: '7'} }
];
console.log( thisMagicFilter(list) );
console.log( thisMagicFilter(list, { type: { name: 'dog'} }) );
console.log( thisMagicFilter(list, { entity: { age: '7'} }) );
console.log( thisMagicFilter(list, { entity: { name: 'Garfield', age: '7'} }) );
console.log( thisMagicFilter(list, { type: { size: 'medium' }, entity: { age: '7'} }) );

Related