Note: I'm still very new to the code-review stack exchange, so if this question does not align with the community guidelines please leave a comment below explaining and I will do my best to modify it to adhere to the community guidelines.
Explanation
I'm attempting to implement a filter()
function that functions most similarly to (I might be wrong in my understanding here) a WHERE
query on a schema-less database that only allows for AND
operators when concatenating WHERE
clauses (no OR
), and =
operators for comparison (no <
, >
, CONTAINS
, etc. operators).
Requirements
I hope this describes the functions expected behavior well enough.
The function should take in an array of objects and a filter. It should return objects within the array that are considered valid within the context of the filter. The filter is a subset of key/values that MUST be present in each object for them to be considered valid within the context of the filter.
Simple Example
Given the data:
const data = [
{
name: 'John',
age: 10
},
{
name: 'Jill',
age: 15
},
{
name: 'Jack',
age: 10
}
];
And the filter:
{
age: 10
}
The results would look like:
[
{
name: 'John',
age: 10
},
{
name: 'Jack',
age: 10
}
]
Code I'd like reviewed
Currently, my function looks like this:
Keep in mind I allow the
data
to also be an object, in which case we get the data array usingObject.values(data);
. This is a requirement of the project I'm implementing this function in. So, please ignore the first few lines of the function and just consider thatdata
is always an Array.
function filter(data, f) {
// Make sure we're dealing with an array, if an object is passed,
// just consider it's values.
let finalData;
if (Array.isArray(data)) {
finalData = data;
}
if (finalData === undefined && typeof data === 'object') {
finalData = Object.values(data);
}
if (finalData === undefined) {
throw new Error('Data being filtered must be either an Array or an Object.');
}
// Define a function to use for filtering the object. This may use recurrsion if one of
// the values in the filter is another object.
const isInFilter = (obj, f) => {
let filterTermsMet = true;
for (const filteredProp in f) {
filterTermsMet = (typeof f[filteredProp] === 'object' && !Array.isArray(f[filteredProp]))
? isInFilter(obj[filteredProp], f[filteredProp])
: obj[filteredProp] === f[filteredProp];
if (!filterTermsMet) {
break;
}
}
return filterTermsMet;
}
// Perform the filter on the final object and return the result.
return finalData.filter(element => {
return isInFilter(element, f);
});
};
Review I'm looking for / Questions I have of peers
Please bear in mind that I'm relatively new to JavaScript/Node.js.
- Am I doing this the expected way within the context of JavaScript/Node.js? I.e is there perhaps some built-in I'm unaware of that performs similar logic or could simplify my function?
- Is there a more efficient way to perform this in JavaScript?
- Is there anything my function isn't taking into consideration, missing in general or overlooking when taking this approach?
- Is it a bad idea to use recursion with the anon function declared in the function when considering sub-objects in the filter? If so, why?
- Any other comments / constructive criticism you might have.
More Complex Examples
Input Data
const objectsArr = [
{
name: 'John',
age: 25,
physical: {
height: 6.2,
weight: 200
}
},
{
name: 'Jason',
age: 24,
physical: {
height: 6.0,
weight: 200
}
},
{
name: 'Jenny',
age: 25,
physical: {
height: 5.3,
weight: 105
}
},
{
name: 'Kevin',
age: 21,
physical: {
height: 5.3,
weight: 189
}
},
{
name: 'Phil',
age: 24,
physical: {
height: 6.0,
weight: 189
}
}
];
Run Filters
let filterToUse;
filterToUse = { // normal condition
age: 25
};
console.log(filterToUse, filter(objectsArr, filterToUse).map(person => person.name));
filterToUse = { // sub-object condition
physical: {
weight: 200
}
};
console.log(filterToUse, filter(objectsArr, filterToUse).map(person => person.name));
filterToUse = { // alternate sub-object condition
physical: {
height: 5.3
}
};
console.log(filterToUse, filter(objectsArr, filterToUse).map(person => person.name));
filterToUse = { // sub-object condition, multiple conditions (AND)
age: 24,
physical: {
height: 6.0
}
};
console.log(filterToUse, filter(objectsArr, filterToUse).map(person => person.name));
Results
{ age: 25 } [ 'John', 'Jenny' ]
{ physical: { weight: 200 } } [ 'John', 'Jason' ]
{ physical: { height: 5.3 } } [ 'Jenny', 'Kevin' ]
{ age: 24, physical: { height: 6 } } [ 'Jason', 'Phil' ]