2

I'm basically trying to implement a search for any given value should look in the array of object key values(there can also be nested objects). Here is an example. The below function will take an object and a query to search in array objects key values. So, if a match is found it should filter from that array.

function searchObj (obj, query) {
  for (var key in obj) {
    var value = obj[key];
    if (typeof value === 'object') {
       searchObj(value, query);
    }
    if (typeof value === 'string' && value.toLowerCase().indexOf(query.toLowerCase()) > -1) {
       return obj;
    }
  }
}

here is the dummy data

var demoData=[
  {id:1,desc:{original:'trans1'},date:'2017-07-16'},
  {id:2,desc:{original:'trans2'},date:'2017-07-12'},
  {id:3,desc:{original:'trans3'},date:'2017-07-11'},
  {id:4,desc:{original:'trans4'},date:'2017-07-15'}
];

here is the array I'm filtering object of the match

var searchFilter = demoData.filter(function(obj){
     return searchObj(obj, 'trans1');
});
console.log(searchFilter);

for example: if I call searchObj(obj,'2017-07-15') it returns that particular object but if I search for trans1 or simply trans it should look into the object and then return the match. I'm kinda stuck now any help would be appreciated. Thanks.

Murali N
  • 3,451
  • 4
  • 27
  • 38

2 Answers2

4

Case 1 is working because you are not hitting the recursion. But in case 2, you are keep searching even after found the result.

return the object once you find.

if (typeof value === 'object') {
       return searchObj(value, query);
    }
    if (typeof value === 'string' && value.toLowerCase().indexOf(query.toLowerCase()) > -1) {
       return obj;
    }

function searchObj (obj, query) {

  for (var key in obj) {
    var value = obj[key];
    if (typeof value === 'object') {
       return searchObj(value, query);
    }
    if (typeof value === 'string' && value.toLowerCase().indexOf(query.toLowerCase()) > -1) {
       return obj;
    }
  }
}

var demoData=[
  {id:1,desc:{original:'trans1'},date:'2017-07-16'},
  {id:2,desc:{original:'trans2'},date:'2017-07-12'},
  {id:3,desc:{original:'trans3'},date:'2017-07-11'},
  {id:4,desc:{original:'trans4'},date:'2017-07-15'}
];

var searchFilter = demoData.filter(function(obj){
     return searchObj(obj, 'trans1');
});
console.log(searchFilter);
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • instead of using for..in i tried to use Object.keys(obj) which doesn't return anything except empty array? – Murali N Aug 21 '17 at 13:08
  • 1
    @MuraliPrasanth Nope. You cannot return from a forEach . https://stackoverflow.com/questions/34653612/what-does-return-keyword-mean-inside-foreach-function – Suresh Atta Aug 21 '17 at 13:13
0

Another way to look at this is to just use JSON.stringify and search within that:

searchObj(obj, string) {
  const regExpFlags = 'gi',
        regExp = new RegExp(string, regExpFlags);
  return JSON.stringify(obj).match(regExp);
}

And then test the search pattern:

var searchFilter = demoData.filter(function(obj){
 return searchObj(obj, 'trans1');
});
console.log(searchFilter);

You can even go further and implement a loose search by providing an array of strings:

searchObj(obj, string) {
 const jsonString = JSON.stringify(obj);
       regExpFlags = 'gi',
       regExpArray = string.split(' ');
       testArray = [];

 regExpArray.forEach(term => {
   let regExp = new RegExp(term, regExpFlags);
   if (jsonString.match(regExp) {
     testArray.push(term);
   }
 });

 return regExpArray.length === testArray.length;
}

I modified the data:

var demoData=[
  {id:1,desc:{original:'trans1'},date:'2017-07-16'},
  {id:1,desc:{original:'trans2'},date:'2017-07-12'},
  {id:1,desc:{original:'trans3'},date:'2017-07-13'},
  {id:2,desc:{original:'trans4'},date:'2017-07-12'},
  {id:3,desc:{original:'trans5'},date:'2017-07-12'},
  {id:4,desc:{original:'trans6'},date:'2017-07-15'},
  {id:1,desc:{original:'trans7'},date:'2017-07-12'}
];

And the search term:

var searchFilter = demoData.filter(function(obj){
 return searchObj(obj, 'trans 2017-07-12');
});
console.log(searchFilter);

One important thing to note here is the performance of JSON.stringify, so this worked fine for me in a case with a limited number of deep nested objects (<1000).

Probably someone with more experience can shed some light on this.

Luka M
  • 176
  • 2
  • 7