Filter array of objects whose any properties contains a value

Viewed 131747

I'm wondering what is the cleanest way, better way to filter an array of objects depending on a string keyword. The search has to be made in any properties of the object.

When I type lea I want to go trough all the objects and all their properties to return the objects that contain lea

When I type italy I want to go trough all the objects and all their properties to return the objects that contain italy.

I know there are lot of solutions but so far I just saw some for which you need to specify the property you want to match.

ES6 and lodash are welcome!

  const arrayOfObject = [{
      name: 'Paul',
      country: 'Canada',
    }, {
      name: 'Lea',
      country: 'Italy',
    }, {
      name: 'John',
      country: 'Italy',
    }, ];

    filterByValue(arrayOfObject, 'lea')   // => [{name: 'Lea',country: 'Italy'}]
    filterByValue(arrayOfObject, 'ita')   // => [{name: 'Lea',country: 'Italy'}, {name: 'John',country: 'Italy'}]

9 Answers

This code checks all the nested values until it finds what it's looking for, then returns true to the "array.filter" for the object it was searching inside(unless it can't find anything - returns false). When true is returned, the object is added to the array that the "array.filter" method returns. When multiple keywords are entered(spaced out by a comma and a space), the search is narrowed further, making it easier for the user to search for something.

Stackblitz example

const data = [
  {
    a: 'aaaaaa',
    b: {
      c: 'c',
      d: {
        e: 'e',
        f: [
          'g',
          {
            i: 'iaaaaaa',
            j: {},
            k: [],
          },
        ],
      },
    },
  },
  {
    a: 'a',
    b: {
      c: 'cccccc',
      d: {
        e: 'e',
        f: [
          'g',
          {
            i: 'icccccc',
            j: {},
            k: [],
          },
        ],
      },
    },
  },
  {
    a: 'a',
    b: {
      c: 'c',
      d: {
        e: 'eeeeee',
        f: [
          'g',
          {
            i: 'ieeeeee',
            j: {},
            k: [],
          },
        ],
      },
    },
  },
];

function filterData(data, filterValues) {
  return data.filter((value) => {
    return filterValues.trim().split(', ').every((filterValue) => checkValue(value, filterValue));
  });
}

function checkValue(value, filterValue) {
  if (typeof value === 'string') {
    return value.toLowerCase().includes(filterValue.toLowerCase());
  } else if (typeof value === 'object' && value !== null && Object.keys(value).length > 0) {
    if (Array.isArray(value)) {
      return value.some((v) => checkValue(v, filterValue));
    } else {
      return Object.values(value).some((v) => checkValue(v, filterValue));
    }
  } else {
    return false;
  }
}

console.log(filterData(data, 'a, c'));
console.log(filterData(data, 'a, c, ic'));

Here is a version of the above which filters by a value which is derived from an array of object's property. The function takes in the array of objects and the specified array of object's property key.

// fake ads list with id and img properties
const ads = [{
  adImg: 'https://test.com/test.png',
  adId: '1'
}, {
  adImg: 'https://test.com/test.png',
  adId: '2'
}, {
  adImg: 'https://test.com/test.png',
  adId: '3'
}, {
  adImg: 'https://test.com/test-2.png',
  adId: '4'
}, {
  adImg: 'https://test.com/test-2.png',
  adId: '5'
}, {
  adImg: 'https://test.com/test-3.png',
  adId: '6'
}, {
  adImg: 'https://test.com/test.png',
  adId: '7'
}, {
  adImg: 'https://test.com/test-6.png',
  adId: '1'
}];

// function takes arr of objects and object property
// convert arr of objects to arr of filter prop values
const filterUniqueItemsByProp = (arrOfObjects, objPropFilter) => {
  return arrOfObjects.filter((item, i, arr) => {
    return arr.map(prop => prop[objPropFilter]).indexOf(item[objPropFilter]) === i;
  });
};

const filteredUniqueItemsByProp = filterUniqueItemsByProp(ads, 'adImg');

console.log(filteredUniqueItemsByProp);

Related