简体   繁体   中英

Javascript generic search of array of objects

I'm trying to come up with a function that allows for a deep generic search of an array of objects, even nested object data like this:

let orders = [
{
  id: 7,
  order_number: 1234
  address: {
    last_name: "Anderson",
    first_name: "John"
  }
},
{
  id: 8,
  order_number: 4321,
  address: {
    last_name: "Franko",
    first_name: "Billy",
  }
}
]

The function needs to be flexible enough to handle any String or Numeric data and search the entire array of objects without needed to know which fields to search for, should search the entire objects fields

So for example something like this would work:

let searchedData = searchData(orders, 'john')

Would return:

[
{
  id: 7,
  order_number: 1234
  address: {
    last_name: "Anderson",
    first_name: "John"
  }
}
]

And

let searchedData = searchData(orders, '4321')

Would return:

[
{
  id: 8,
  order_number: 4321,
  address: {
    last_name: "Franko",
    first_name: "Billy",
  }
}
]

This would need to be able to work to unlimited levels deep, the depth of the objects will not be known.

It also needs to be case insensitive.

I did the following function:

searchData(arr, query) {
  let data = [];

  for(let item of arr) {
    if(item.order_number.includes(query) || item.address.last_name.toLowerCase().includes(query) ||   item.address.first_name.toLowerCase().includes(query)) {
      data.push(item);
    }
  }
}

The problem is this function isn't abstract enough to work with any array of objects.

Just modify it a bit:

 searchData(arr, query) { let data = []; let re = new RegExp(query, 'i'); for (let item of arr) { for (let p in item) { if (re.test(item[p])) data.push(item[p]); } } return data; }

I use regex so that it's case-insensitive, and return the "data" var at the end (which is important). This isn't recursive, so it won't handle your nested objects, but you can add that in pretty easily but just testing the type of item[p], running the function and merging what's returned. However, you won't get the property of what's being searched, and that may be what you're after. For that, you would need to push a new object instead of just the value. But hopefully this helps some.

You can use a simple recursive inner function. You may need to modify the matching condition to suit your needs.

 let orders = [ { id: 7, order_number: 1234, address: { last_name: "Anderson", first_name: "John" } }, { id: 8, order_number: 4321, address: { last_name: "Franko", first_name: "Billy", } } ]; function searchData(data, val){ function find(data){ if(data===val||data.toString && val.toString && data.toString().toLowerCase().includes(val.toString().toLowerCase()))return true;//you can modify the matching condition return data===Object(data) && Object.values(data).some(find); } return (Array.isArray(data)?data:Object.values(data)).filter(find); } console.log(searchData(orders, 'John')); console.log(searchData(orders, '4321'));

You could take a recursive approach by looking to objects and find in the values.

 const searchData = (data, val) => { const isObject = o => o && typeof o === 'object', find = o => o === val || o.toString() === val.toString() || isObject(o) && Object.values(o).some(find); return data.filter(find); }; let orders = [ { id: 7, order_number: 1234, address: { last_name: "Anderson", first_name: "John" } }, { id: 8, order_number: 4321, address: { last_name: "Franko", first_name: "Billy", } } ]; console.log(searchData(orders, 'John')); console.log(searchData(orders, '4321'));
 .as-console-wrapper { max-height: 100%;important: top; 0; }

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM