I have this data structure:
const data = [
{ name: 'John', age: 36, color: {red: 243, green: 22, blue: 52} },
{ name: 'Jane', age: 28, color: {red: 23, green: 62, blue: 15} },
{ name: 'Lisa', age: 42, color: {red: 89, green: 10, blue: 57} }
]
And I want to filter it based on a list of conditions, like this (filter
property is mapped to a predicate function from ramda):
const definitions = [
{
id: 'name',
filter: 'includes',
path: [],
},
{
id: 'age',
filter: 'gte',
path: [],
value: 36
}
]
Using this code works fine for properties that is directly on the object:
const Operations = {
includes,
equals,
gte
}
const filters = reduce((a, c) => {
a[c.id] = c.value ? Operations[c.filter](c.value) : always(true);
return a;
}, {}, definitions)
filter(where(filters), data);
Problem is, I want to introduce other filter conditions that operate on nested structures. For that I introduced a path property, that would take an array of strings that represents the path where the property is located on the object:
const definitions = [
{
id: 'name',
filter: 'includes',
path: [],
},
{
id: 'age',
filter: 'gte',
path: [],
value: 36
},
{
id: 'red',
filter: 'gte',
path: ['color', 'red'],
value: 40
},
{
id: 'blue',
filter: 'gte',
path: ['color', 'blue']
}
]
This should result in (filters only take effect when there is a value
exist in the definition):
{
age: 36,
color: {
blue: 52,
green: 22,
red: 243
},
name: "John"
}
However, I can’t make it work with where
.
I could pre-map the array to bring the nested
properties to the uppermost level of the objects, but I guess there is a more elegant way.
2
Answers
I found out eventually, just have to drop
where
and change it to useallPass
:And change the reducer to:
I’d suggest
pathSatisfies
but you’d have to switchgte
forlte
.