JS search in object values

I have an array of homogeneous objects like so;

[
  {
    "foo" : "bar",
    "bar" : "sit"
  },
  {
    "foo" : "lorem",
    "bar" : "ipsum"
  },
  {
    "foo" : "dolor",
    "bar" : "amet"
  }
]

I'd like to search these objects' values (not keys) with a keyword, and return an array of objects that contain the keyword in any of the values.

So for example, with a keyword r, I would get all the objects ("baR" in object #1, "loRem" in object #2 and "doloR" in object #3). With a keyword lo, I would get objects 2 and 3 ("LOrem" and "doLOr"), with a, I'd get objects 1 and 3, ("bAr" and "Amet"). With the keyword foo however, I would get an empty array, since "foo" is a key, and isn't found in any of the values (unlike "bar")... you get the idea.

How would I go about doing this? Thanks a lot in advance!

Answers:

Answer

All the other old answers use a for in loop, modern JavaScript has Object.keys. Combine that with some, includes, and filter and it is a bit nicer.

var a = [{
  name: 'xyz',
  grade: 'x'
}, {
  name: 'yaya',
  grade: 'x'
}, {
  name: 'x',
  frade: 'd'
}, {
  name: 'a',
  grade: 'b'
}];

function filterIt(arr, searchKey) {
  return arr.filter(function(obj) {
    return Object.keys(obj).some(function(key) {
      return obj[key].includes(searchKey);
    })
  });
}

console.log("find 'x'", filterIt(a,"x"));
console.log("find 'a'", filterIt(a,"a"));
console.log("find 'z'", filterIt(a,"z"));

Or with ES6

function filterIt(arr, searchKey) {
  return arr.filter(obj => Object.keys(obj).some(key => obj[key].includes(searchKey)));
}
Answer

The search function will return all objects which contain a value which has contains the search query

function search(arr, s){
    var matches = [], i, key;
    
    for( i = arr.length; i--; )
        for( key in arr[i] )
            if( arr[i].hasOwnProperty(key) && arr[i][key].indexOf(s) > -1 )
                matches.push( arr[i] );  // <-- This can be changed to anything

    return matches;
};

// dummy data
var items = [
      {
        "foo" : "bar",
        "bar" : "sit"
      },
      {
        "foo" : "lorem",
        "bar" : "ipsum"
      },
      {
        "foo" : "dolor",
        "bar" : "amet"
      }
];
    
var result = search(items, 'lo'); // search "items" for a query value
console.log(result); // print the result

Answer

This is a cool solution that works perfectly

const array = [{"title":"tile hgfgfgfh"},{"title":"Wise cool"},{"title":"titlr DEytfd ftgftgfgtgtf gtftftft"},{"title":"This is the title"},{"title":"yeah this is cool"},{"title":"tile hfyf"},{"title":"tile ehey"}];

var item = array.filter(item=>item.title.toLowerCase().includes('this'));

 alert(JSON.stringify(item))

EDITED

const array = [{"title":"tile hgfgfgfh"},{"title":"Wise cool"},{"title":"titlr DEytfd ftgftgfgtgtf gtftftft"},{"title":"This is the title"},{"title":"yeah this is cool"},{"title":"tile hfyf"},{"title":"tile ehey"}];


// array.filter loops through your array and create a new array returned as Boolean value given out "true" from eachIndex(item) function 

var item = array.filter((item)=>eachIndex(item));

//var item = array.filter();



function eachIndex(e){
console.log("Looping each index element ", e)
return e.title.toLowerCase().includes("this".toLowerCase())
}

console.log("New created array that returns \"true\" value by eachIndex ", item)

Answer

This is a propoosal which uses the key if given, or all properties of the object for searching a value.

function filter(array, value, key) {
    return array.filter(key
        ? a => a[key] === value
        : a => Object.keys(a).some(k => a[k] === value)
    );
}

var a = [{ name: 'xyz', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }];


console.log(filter(a, 'x'));
console.log(filter(a, 'x', 'name'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer

As a Javascripter Lv. 1 I just learned to search for strings in objects with this:

function isThere( a_string, in_this_object )
{
    if( typeof a_string != 'string' )
    {
        return false;
    }

    for( var key in in_this_object )
    {
        if( typeof in_this_object[key] == 'object' || typeof in_this_object[key] == 'array' )
        {
            if ( isThere( a_string, in_this_object[key] ) )
            {
                return true;
            }
        }
        else if( typeof in_this_object[key] == 'string' )
        {
            if( a_string == in_this_object[key] )
            {
                return true;
            }
        }
    }

    return false;
}

I know is far from perfect but it is useful.

Feel free to comment in order to improve this.

Answer
var search(subject, objects) {

    var matches = [];
    var regexp = new RegExp(subject, 'g');

    for (var i = 0; i < objects.length; i++) {
        for (key in objects[i]) {
            if (objects[i][key].match(regexp)) matches.push(objects[i][key]);
        }
    }
    return matches;
};

var items = [
  {
    "foo" : "bar",
    "bar" : "sit"
  },
  {
    "foo" : "lorem",
    "bar" : "ipsum"
  },
  {
    "foo" : "dolor",
    "bar" : "amet"
  }
];

search('r', items);    // ["bar", "lorem", "dolor"]
Answer

Here is the answer in 100% PURE JavaScript:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<script type="text/javascript">

var mySet = [
    {
    "foo" : "bar",
    "bar" : "sit"
    },
    {
    "foo" : "lorem",
    "bar" : "ipsum"
    },
    {
    "foo" : "dolor",
    "bar" : "amet"
    }
];

function queryObject(needle, set){
    var results = new Array();
    for(index=0;index<set.length;index++){
        for(key in set[index]){
            if(set[index][key].indexOf(needle) > -1){
                results.push(set[index]);
            }
        }
    }

    if(results.length){
        return JSON.stringify(results);
    }else{
        return "No match!";
    }
}

</script>
</head>
<body>
<form>
    <input type="text" id="prompt" onFocus="this.value='';" value="Type your query HERE" size="20" onKeyDown="document.getElementById('submit').disabled = false;">
    <input id="submit" type="button" value="Find in Object" onClick="var prompt=document.getElementById('prompt'); if(prompt.value){document.getElementById('output').innerHTML = queryObject(prompt.value, mySet);}else{prompt.value='Type your query HERE';}" disabled="disabled">
    <div id="output"></div>
</form>
</body>
</html>

There are, of course, more fancy ways to traverse your object using JQuery, but this is the basic concept.

Cheers!

*EDIT: Sorry, I didn't read your question carefully enough, and modified the code to return an array of objects as you requested.

Answer

Although a bit late, but a more compact version may be the following:

/**
* @param {string} quickCriteria Any string value to search for in the object properties.
* @param {any[]} objectArray The array of objects as the search domain
* @return {any[]} the search result
*/
onQuickSearchChangeHandler(quickCriteria, objectArray){

   let quickResult = objectArray.filter(obj => Object.values(obj).some(val => val?val.toString().toLowerCase().includes(quickCriteria):false));

   return quickResult;
}

It can handle falsy values like false, undefined, null and all the data types that define .toString() method like number, boolean etc.

Answer

Just another variation using ES6, this is what i use.

// searched keywords    
const searchedWord = "My searched exp";

// array of objects
let posts = [
    {
        text_field: "lorem ipsum doleri imet",
        _id: "89789UFJHDKJEH98JDKFD98"
    }, 
    {
        text_field: "ipsum doleri imet",
        _id: "JH738H3JKJKHJK93IOHLKL"
];

// search results will be pushed here
let matches = [];

// regular exp for searching
let regexp = new RegExp(searchedWord, 'g');

// looping throuth posts to fing the word
posts.forEach((post) => {
    if (post["text_field"].match(regexp)) matches.push(post);
});
Answer

I needed to perform a search on a large object and return the addresses of the matches, not just the matched values themselves.

This function searches an object for a string (or alternatively, uses a callback function to perform custom logic) and keeps track of where the value was found within the object. It also avoids circular references.

//Search function
var locateInObject = function(obj, key, find, result, currentLocation){
  if(obj === null) return;
  result = result||{done:[],found:{}};
  if(typeof obj == 'object'){
    result.done.push(obj);
  }
  currentLocation = currentLocation||key;
  var keys = Object.keys(obj);
  for(var k=0; k<keys.length; ++k){
    var done = false;
    for(var d=0; d<result.done.length; ++d){
      if(result.done[d] === obj[keys[k]]){
        done = true;
        break;
      }
    }
    if(!done){
      var location = currentLocation+'.'+keys[k];
      if(typeof obj[keys[k]] == 'object'){
        locateInObject(obj[keys[k]], keys[k], find, result, location)
      }else if((typeof find == 'string' && obj[keys[k]].toString().indexOf(find) > -1) || (typeof find == 'function' && find(obj[keys[k]], keys[k]))){
        result.found[location] = obj[keys[k]];
      }
    }
  }
  return result.found;
}

//Test data
var test = {
  key1: {
    keyA: 123,
    keyB: "string"
  },
  key2: {
    keyC: [
      {
        keyI: "string123",
        keyII: 2.3
      },
      "string"
    ],
    keyD: null
  },
  key3: [
    1,
    2,
    123,
    "testString"
  ],
  key4: "123string"
}
//Add a circular reference
test.key5 = test;

//Tests
console.log(locateInObject(test, 'test', 'string'))
console.log(locateInObject(test, 'test', '123'))
console.log(locateInObject(test, 'test', function(val, key){ return key.match(/key\d/) && val.indexOf('string') > -1}))

Answer

Below shared for specific given property

searchContent:function(s, arr,propertyName){
            var matches = [];
            var propertyNameString=this.propertyNameToStr(propertyName);
            for (var i = arr.length; i--; ){
                if((""+Object.getOwnPropertyDescriptor(arr[i], propertyNameString).value).indexOf(s) > -1)
                    matches.push(arr[i]);
            }
            return matches;
        },
    propertyNameToStr: function (propertyFunction) {
            return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1];
    }

//usage as below

result=$localStorage.searchContent(cabNo,appDataObj.getAll(),function() { dummy.cabDriverName; })
Answer

I've found a way that you can search in nested object like everything search , for example list of student that have nested lesson object:

var students=[{name:"ali",family:"romandeh",age:18,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]},
   {name:"hadi",family:"porkar",age:48,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]},
   {name:"majid",family:"porkar",age:30,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]}
   ];
  
    function searchInChild(objects, toSearch){
        var _finded=false;
        for(var i=0; i<objects.length; i++) {
            for(key in objects[i]) {
                if(objects[i][key]!=null && typeof(objects[i][key] )!="boolean" && typeof(objects[i][key] )!="number"){
                    if (typeof objects[i][key] == 'object') {
                        _finded= searchInChild(objects[i][key],toSearch);

                    }
                    else if(objects[i][key].indexOf(toSearch)!=-1) {
                        _finded=true;
                    }
                }
            }
        }
        return _finded;
    }
    function findNested(objects, toSearch) {
        var _results=[];
        for(var i=0; i<objects.length; i++) {
            for(key in objects[i]) {
                if(objects[i][key]!=null && typeof(objects[i][key] )!="boolean" && typeof(objects[i][key] )!="number"){
                    if (typeof objects[i][key] == 'object') {
                        if(searchInChild(objects[i][key],toSearch)){
                            _results.push(objects[i]);
                        }
                    }
                    else if(objects[i][key].indexOf(toSearch)!=-1) {
                        _results.push(objects[i]);
                    }
                }
            }
        }

        return _results;

    }
    $('.quickSearch').on('click',function(){
          var _inputSeach=$('#evertingSearch').val();
          if(_inputSeach!=''){
          var _finded=findNested(students,_inputSeach);
          $('.count').html(_finded.length);}
    
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
<span>
<pre><code>
       var students=[{name:"ali",family:"romandeh",age:18,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]},
   {name:"hadi",family:"porkar",age:48,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]},
   {name:"majid",family:"rezaeiye",age:30,curse:[
   {lesson1:"arabic"},
   {lesson2:"english"},
   {lesson3:"history"}
   ]}
   ];
</code></pre>

<span>

<input id="evertingSearch" placeholder="Search on students" />
<input type="button" class="quickSearch" value="search" />
<lable>count:</lable><span class="count"></span>


</body>



</html>

Answer

Came across this problem today and using a modified version of the provided code by epascarello did the trick, because that version had trouble when the object contained some values others than strings (like a number of booleans for example).

console.log('find: ', findIn(arrayOfObjects, searchKey));

const findIn = (arr, searchKey) => {
 return arr.filter(obj => 
  Object.keys(obj).some(key => {
   if (typeof obj[key] === 'string') {
    return obj[key].includes(searchKey);
   }
  })
 );
};
Answer
search(searchText) {
  let arrayOfMatchedObjects = arrayOfAllObjects.filter(object => {
    return JSON.stringify(object)
      .toString()
      .toLowerCase()
      .includes(searchText);
  });
  return arrayOfMatchedObjects;
}

This could be very simple, easy, fast and understandable Search function for some of you just like me.

Answer

Something like this:

var objects = [
  {
    "foo" : "bar",
    "bar" : "sit"
  },
  {
    "foo" : "lorem",
    "bar" : "ipsum"
  },
  {
    "foo" : "dolor",
    "bar" : "amet"
  }
];

var results = [];

var toSearch = "lo";

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 results array will contain all matched objects.

If you search for 'lo', the result will be like:

[{ foo="lorem", bar="ipsum"}, { foo="dolor", bar="amet"}]

NEW VERSION - Added trim code, code to ensure no duplicates in result set.

function trimString(s) {
  var l=0, r=s.length -1;
  while(l < s.length && s[l] == ' ') l++;
  while(r > l && s[r] == ' ') r-=1;
  return s.substring(l, r+1);
}

function compareObjects(o1, o2) {
  var k = '';
  for(k in o1) if(o1[k] != o2[k]) return false;
  for(k in o2) if(o1[k] != o2[k]) return false;
  return true;
}

function itemExists(haystack, needle) {
  for(var i=0; i<haystack.length; i++) if(compareObjects(haystack[i], needle)) return true;
  return false;
}

var objects = [
  {
    "foo" : "bar",
    "bar" : "sit"
  },
  {
    "foo" : "lorem",
    "bar" : "ipsum"
  },
  {
    "foo" : "dolor blor",
    "bar" : "amet blo"
  }
];

function searchFor(toSearch) {
  var results = [];
  toSearch = trimString(toSearch); // trim it
  for(var i=0; i<objects.length; i++) {
    for(var key in objects[i]) {
      if(objects[i][key].indexOf(toSearch)!=-1) {
        if(!itemExists(results, objects[i])) results.push(objects[i]);
      }
    }
  }
  return results;
}

console.log(searchFor('lo '));
Answer

You can use this javascript lib, DefiantJS (http://defiantjs.com), with which you can filter matches using XPath on JSON structures. To put it in JS code:

    var data = [
       { "foo": "bar",   "bar": "sit" },
       { "foo": "lorem", "bar": "ipsum" },
       { "foo": "dolor", "bar": "amet" }
    ],
    res1 = JSON.search( data, '//*[contains(name(), 'r')]/..' ),
    res2 = JSON.search( data, '//*[contains(., 'lo')]' );

/*
res1 = [
    { "foo": "bar",   "bar": "sit" },
    { "foo": "lorem", "bar": "ipsum" },
    { "foo": "dolor", "bar": "amet" }
]
*/

/*
res2 = [
    { "foo": "lorem", "bar": "ipsum" },
    { "foo": "dolor", "bar": "amet" }
]
*/

Here is a working fiddle;
http://jsfiddle.net/hbi99/2kHDZ/

DefiantJS extends the global object with the method "search" and returns an array with matches (empty array if no matches were found). You can try out the lib and XPath queries using the XPath Evaluator here:

http://www.defiantjs.com/#xpath_evaluator

Answer

I have created this easy to use library that does exactly what you are looking for: ss-search

import { search } from "ss-search"

const data = [
  {
       "foo" : "bar",
       "bar" : "sit"
  },
  {
       "foo" : "lorem",
       "bar" : "ipsum"
  },
  {
       "foo" : "dolor",
       "bar" : "amet"
  }
]
const searchKeys = ["foor", "bar"] 
const searchText = "dolor"

const results = search(data, keys, searchText)
// results: [{ "foo": "dolor", "bar": "amet" }]
Answer

You can use the _filter method of lodash:

return _filter((item) => item.name.includes("fo"),tempObjectHolder);
Answer

Modern Javascript ????

const objects = [
    {
        "foo" : "bar",
        "bar" : "sit"
    },
    {
        "foo" : "lorem",
        "bar" : "ipsum"
    },
    {
        "foo" : "dolor blor",
        "bar" : "amet blo"
    }
];

const keyword = 'o';

const results = objects.filter(object => Object.values(object).some(i => i.includes(keyword)));
console.log(results);

// results [{ foo: 'lorem', bar: 'ipsum' },{ foo: 'dolor blor', bar: 'amet blo' }]

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.