Tengo una matriz de la forma
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.... ]
Estoy tratando de filtrar, digamos así:
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);
Pero la función no funciona como debería. Si el objeto tiene un valor en la propiedad, filtra, pero si hay varios y necesito al menos uno para satisfacer la búsqueda, entonces no filtra. Ayuda quien pueda por favor
Puede verificar si el valor de "filterKey" no es una matriz, convertirlo en una matriz y verificar si una matriz tiene una submatriz
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); }); }); }
Supongo que tiene la intención de implementar una funcionalidad OR
porque dijo al menos una de ellas . Por lo tanto, el código de trabajo está debajo.
Pero antes de seguir leyendo, tenga cuidado con los siguientes comentarios:
Usé some
en lugar de every
, porque some
funciona como or
y every
funciona como and
. Significa que esa línea devolverá verdadero si el elemento de car
actual coincide con al menos uno de los filtros.
Debe usar item.includes(filter)
en lugar de filter.includes(item)
.
Debe verificar si el elemento de filtro actual es una matriz o no, y actuar en consecuencia.
En este código no manejé eso y asumí que currentCandidate
es una cadena o una primitiva. Si hay otros casos en los que el elemento candidato (es decir, un campo del car
) también es una matriz, entonces debe actualizar el código para manejar eso también.
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)
Puede verificar si la consulta es una matriz y/o el valor es una matriz y verificar en consecuencia.
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));