I have an array of the form
var cars = [
{name: "BMW X5", topsales: ["USA", "China", "Russia"], maxspeed: 250, users: ["teenage", "ladies", "mens"]}
{name: "Volkswagen Touareg", topsales: ["USA", "Germany"], maxspeed: 240, users: ["teenage", "mens", "old mens"]}
etc....
]
I am trying to filter, let's say like this:
var query = {
topsales: ["USA", "China"],
users: "teenage"
}
function nestedFilter(targetArray, filters) {
var filterKeys = Object.keys(filters);
return targetArray.filter(function (eachObj) {
return filterKeys.every(function (eachKey) {
if (!filters[eachKey].length) {
return true;
}
return filters[eachKey].includes(eachObj[eachKey]);
});
});
};
goodresult = nestedFilter(cars, query);
But the function doesn't work as it should. If the object has one value in the property, then it filters, but if there are several of them, and I need at least one of them to satisfy the search, then it does not filter. Help who can please
CodePudding user response:
You could check if query is an array and/or the value is an array and check accordingly.
function nestedFilter(data, query) {
const
filters = Object.entries(query);
return data.filter(o => filters.every(([k, v]) => Array.isArray(v)
? Array.isArray(o[k])
? v.some(s => o[k].includes(s))
: v.includes(o[k])
: Array.isArray(o[k])
? o[k].includes(v)
: o[k] === v
));
}
const
cars = [{ name: "BMW X5", topsales: ["USA", "China", "Russia"], maxspeed: 250, users: ["teenage", "ladies", "mens"] }, { name: "Volkswagen Touareg", topsales: ["USA", "Germany"], maxspeed: 240, users: ["teenage", "mens", "old mens"] }],
query = { topsales: ["USA", "China"], users: "teenage" };
console.log(nestedFilter(cars, query));
CodePudding user response:
I am assuming that you intend to implement an OR
functionality because you said at least one of them. Therefore the working code is below.
But before going on reading, please beware of below remarks:
I used
some
instead ofevery
, becausesome
works asor
andevery
works asand
. It means that that line will return true if the currentcar
item matches at least one of the filters.You should use
item.includes(filter)
instead offilter.includes(item)
.You need to check if the current filter item is an array or not, and act accordingly.
In this code I didn't handle that and assumed that
currentCandidate
is a string or a primitive. If there are other cases where the candidate item (i.e. a field of thecar
) itself is also an array, then you have to update the code to also handle that.
var cars = [
{name: "BMW X5", topsales: "USA, China, Russia", maxspeed: 250, users: "teenage, ladies, men"},
{name: "Volkswagen Touareg", topsales: "USA, Germany", maxspeed: 240, users: "teenage, men, old men"}
]
var query = {
topsales: ["USA", "China"],
maxspeed: 240
}
function nestedFilter(targetArray, filters) {
const filterKeys = Object.keys(filters);
return targetArray.filter(function (eachObj) {
//using some instead of every to make sure that it works as OR
const result = filterKeys.some(function (eachKey) {
//the current item that we are trying to use in the filter
const currentCandidate = eachObj[eachKey];
//the current item that we are using as a filter
const currentFilterItem = filters[eachKey]
if (Array.isArray(currentFilterItem)) {
if (currentFilterItem.length === 0) {
//no filter, return true
return true
}
//loop on each item in the currentFilterItem
//if any of them matches simply return true (OR)
for (let filterKey in currentFilterItem) {
if (currentCandidate.includes(currentFilterItem[filterKey])) {
return true
}
}
//for loop ended, no match
return false
} else {
//the current filter item is not an array, use it as one item
//return eachObj[eachKey].includes(currentFilterItem)
return currentCandidate === currentFilterItem
}
});
return result;
});
}
goodresult = nestedFilter(cars, query);
console.debug(goodresult)
CodePudding user response:
You can check if the value of the "filterKey" is not an array, make it an array, and check if an array has a subArray
function hasSubArray(master, sub) {
return sub.every((i => v => i = master.indexOf(v, i) 1)(0));
}
function nestedFilter(targetArray, filters) {
var filterKeys = Object.keys(filters);
return targetArray.filter(function (eachObj) {
return filterKeys.every(function (eachKey) {
var subArray = filters[eachKey];
if (!Array.isArray(filters[eachKey])) {
subArray = [filters[eachKey]];
}
return hasSubArray(eachObj[eachKey], subArray);
});
});
}