简体   繁体   中英

Search/Filter JavaScript Object Array

I am trying to create a search/filter function that allows users to filter an array of JS objects which returns an array populated with data matching the search query.

I wish to be able to search multiple properties in one query so for example; if I search HKG it would return all 3 of the objects but if I searched HKG 12345 it would return the first object in the array.

Another example would be if I were to search 8 it would return the first 2 objects in the array from sumOfContainers property matching the query but if I searched 8 SAV it would return only the first object.

results = [];

objects = [
        {laneId:"12345", lane:"HKG-SAV", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
        {laneId:"12346", lane:"HKG-FRA", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
        {laneId:"12347", lane:"HKG-LAX", equipmentType:"20'STD", sumOfContainers: "9", baseline:"$1234", new:"$1234", newSaving:"$1234"},     
];

const Search = (toSearch) => {
 for(var i=0; i<objects.length; i++) {
   for(key in objects[i]) {
     if(objects[i][key].indexOf(toSearch)!=-1) {
       results.push(objects[i]);
     }
   }
  }
}

The problem with my attempt is that it will return duplicate data. I have come across a lot of posts online but I am finding difficulty trying to find posts seeking as similar result.

I am trying to achieve this with native JavaScript.

Some issues:

  • The duplicates get added because after adding an object, you keep looking for more matches in the same object. So if there is any other key that matches, the same object will be added twice

  • When the search includes a space, your description says you want to treat that as a separator for multiple search terms, but your code never splits the search argument like that.

  • There is no return statement in your function

  • The key variable is not declared with var , let or const

I would suggest solving this with filter : this guarantees that you won't get duplicates. Then require that all search terms have a match: for this you can use split and every . Then require that there is at least one key that matches a search term: for this you can use some :

Don't name your search function with PascalCase, but with camelCase (so search instead of Search ). The common practice is that PascalCase is reserved for constructor/class names.

const search = toSearch => {
 let terms = toSearch.split(" ");
 return objects.filter(object =>
   terms.every(term =>
     Object.values(object).some(value =>
       value.includes(term)
     )
   )
  );
}

I came up with quite a lousy way of achieving the conditions in the question. If anyone can make this code more optimal that would be terrific.

  const search = () => {
      let toSearch = document.getElementById("search").value;
      let lanes = this.objects;
      let result = [];
      const filters = toSearch.split(" ");
      for(let i = 0; i <lanes.length; i++) {
        let search = "";
        let isMatched = true;
        for(let key in lanes[i]) {
            search += lanes[i][key] + " ";
        }
        filters.forEach(filter => {
          if(search.indexOf(filter) == -1) {
            isMatched = false;
            break;
          } 
        });
        if(isMatched) {
          result.push(lanes[i]);
        }
      }
      return result;
    }

If you don't mind lodash :

const _ = require('lodash');

const objects = [
        {laneId:"12345", lane:"HKG-SAV", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
        {laneId:"12346", lane:"HKG-FRA", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
        {laneId:"12347", lane:"HKG-LAX", equipmentType:"20'STD", sumOfContainers: "9", baseline:"$1234", new:"$1234", newSaving:"$1234"},     
];

const mySearch = (arr, text) => {
  const includesValue = (word, obj) => _.some(obj, (value) => _.includes(value, word));
  const words = _.words(text); 
  return arr
    .filter((obj) => 
      words.every((word) => 
        includesValue(word, obj)
      )
    );
};

console.log(mySearch(objects, 'HKG 12345'));
// [{laneId: '12345', lane: 'HKG-SAV', equipmentType: "20'STD", sumOfContainers: '8', baseline: '$1234', new: '$1234', newSaving: '$1234' }]

console.log(mySearch(objects, '8'));
// [
//   {laneId:"12345", lane:"HKG-SAV", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
//   {laneId:"12346", lane:"HKG-FRA", equipmentType:"20'STD", sumOfContainers: "8", baseline:"$1234", new:"$1234", newSaving:"$1234"},
// ]

console.log(mySearch(objects, '8 SAV'));
// [{laneId: '12345', lane: 'HKG-SAV', equipmentType: "20'STD", sumOfContainers: '8', baseline: '$1234', new: '$1234', newSaving: '$1234' }]

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