2

I have an array of objects that I am filtering through based on a query. If the query matches a title inside the array of objects I return it.

  const arr = [{ title: 'Xbox one controller' }];

  const filterResults = arr.filter((item) =>
    item.title.toLowerCase().includes(req.query.q.toLowerCase())
  );

  res.send(filterResults);

These words if I just search on a word like "xbox", however, if I search "xbox controller" it returns nothing.

I was thinking of splitting req.query like this: const reqy = req.query.q.split(' ') and using those as keywords although I don't really know where to start. Another potential problem with my "solution" is that if a query looks like "Controller for Xbox One" will the result even show up?

My problem is making the filter function accept multiple "keywords" derived from the user query.

Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
user
  • 1,022
  • 2
  • 8
  • 30
  • Familiarize yourself with [how to access and process nested objects, arrays or JSON](https://stackoverflow.com/q/11922383/4642212) and how to [create objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer) and use the available [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Static_methods) and [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Static_methods) methods (both static and on prototype). – Sebastian Simon Mar 09 '21 at 01:39
  • Look at [`some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) and [`every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every). – Sebastian Simon Mar 09 '21 at 01:39
  • @SebastianSimon I have, the problem I found is that they only return boolean values and I'm unable to return the actual result – user Mar 09 '21 at 01:41
  • Yes, they return booleans, and `filter` works well with booleans. Use them inside `filter`. – Sebastian Simon Mar 09 '21 at 01:43

3 Answers3

1

You can use split & some (or every if you want all words are matched) to achieve your expected result.

  • split: Split a string into an array of substrings:
  • some: The some() method tests whether at least one element in the array passes the test implemented by the provided function
  • every: The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.
    const arr = [{ title: 'Xbox one controller' }];
    
    const query = 'xbox controller2';
    const splitedQuery = query.split(' ');
    
    const filterResults = arr.filter(item => {
      let splitedTitle = item.title.split(' ');
      return splitedTitle.some(r => splitedQuery.some(q => r.toLowerCase() == q.toLowerCase()));
    });
    
    console.log(filterResults);
Nguyễn Văn Phong
  • 13,506
  • 17
  • 39
  • 56
1

There are many ways to do it. Here is one example for you.

const arr = [{ title: 'Xbox one controller' }];
const req = { query: { q: 'Xbox controller' } }

  const filterResults = arr.filter((item) => {
   const queries = req.query.q.split(' ');
   return queries.find((text) => item.title.toLowerCase().includes(text.toLowerCase()))
  });
  
  console.log(filterResults)
Yadab
  • 1,767
  • 1
  • 10
  • 16
1

One possible solution is to check whether every word in your search term occurs in the title. You can call the split method on your searchTerm to get an array of words in the search term. Then call the every method to verify whether all of the words in the search term appear in the title. As before, you can still use the filter method to remove those entries whose titles do not contain all of the words in the search term.

const searchTerm = 'xbox controller';

const arr = [{ title: 'Xbox one controller' }];

const filterResults = arr.filter(({ title }) =>
  searchTerm
    .toLowerCase()
    .split(' ')
    .every(keyword => title.toLowerCase().includes(keyword))
);
greenBox
  • 552
  • 4
  • 5