Given a search string:
Jane
and this array of objects:
[
{
name: 'Jane Smith',
address: '123 Main St, Boston, MA 01234',
telephone: {
primary: '1234567890',
secondary: '1112223333'
}
},
{
name: 'John Smith',
address: '333 Main St, New York, NY 56789',
telephone: {
primary: '2223334444',
secondary: '3334445555'
}
},
...
]
we can filter the array by name:
arr.filter(person => person.name.includes(search))
Great. That works well if all we are only searching by each object's name
property.
What is the best practice for filtering across all properties of an object?
Do we have to do something like:
arr.filter(person =>
person.name.includes(search) ||
person.address.includes(search) ||
person.telephone.primary.includes(search) ||
person.telephone.secondary.includes(search)
)
This becomes tedious and error prone if there are more than a couple properties.
Is there a way to filter an array if any property's value matches a search string?
Update:
This works nicely for top level properties on the person object.
.filter(person => {
for (let property in person) {
return String(person[property]).includes(search)
}
})
Working on trying to find a nice solution for recursively searching through properties that may themselves be objects.
Use Object.keys
and Array#some
in a recursive function (I have called it deepIncludes
) to check if any property (or sub-property) includes the search string. Here I have used this
to store the search string, because that allows you to filter
your array of people with this syntax:
let result = array.filter(deepIncludes, 'Search String')
function deepIncludes (object) { return Object.keys(object).some(k => { let v = object[k] return (v && typeof v == 'object') ? deepIncludes.call(this, v) : String(v).includes(this) }) } let array = [ { name: 'Jane Smith', address: '123 Main St, Boston, MA 01234', telephone: { primary: '1234567890', secondary: '1112223333' } }, { name: 'John Smith', address: '333 Main St, New York, NY 56789', telephone: { primary: '2223334444', secondary: '3334445555' } } ] // Usage: console.log( array.filter(deepIncludes, '3334445555') //=> [ { name: 'John Smith', ... } ] )
You can use JSON.stringify
with the replacer
parameter as a way to traverse the object.
function search(obj, str) {
var found = false;
JSON.stringify(obj, (key, value) => {
if (!found && typeof value === 'string' && value.includes(str)) found = true;
else return value;
});
return found;
}
In the end I chose something close to this:
function search (obj, text) {
for (let prop in obj) {
if (String(obj[prop]).includes(text)) {
return true
} else if (typeof obj[prop] === 'object') {
return search(obj[prop], text)
}
}
}
Usage:
.filter(person => search(person, text))
Update:
The for...in
method does not work well for my use case. I'm not sure why, but some keys are not searched.
Using the Object.keys
method works perfectly.
function search (obj, text) {
return Object.keys(obj).some(k =>
typeof obj[k] === 'object'
? search(obj[k], text)
: String(obj[k]).includes(text)
)
}
(same usage)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.