[javascript] 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!

This question is related to javascript json search

The answer is


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.


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"]

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


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

_x000D_
_x000D_
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"}];_x000D_
_x000D_
_x000D_
// array.filter loops through your array and create a new array returned as Boolean value given out "true" from eachIndex(item) function _x000D_
_x000D_
var item = array.filter((item)=>eachIndex(item));_x000D_
_x000D_
//var item = array.filter();_x000D_
_x000D_
_x000D_
_x000D_
function eachIndex(e){_x000D_
console.log("Looping each index element ", e)_x000D_
return e.title.toLowerCase().includes("this".toLowerCase())_x000D_
}_x000D_
_x000D_
console.log("New created array that returns \"true\" value by eachIndex ", item)
_x000D_
_x000D_
_x000D_


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:

_x000D_
_x000D_
var students=[{name:"ali",family:"romandeh",age:18,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]},_x000D_
   {name:"hadi",family:"porkar",age:48,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]},_x000D_
   {name:"majid",family:"porkar",age:30,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]}_x000D_
   ];_x000D_
  _x000D_
    function searchInChild(objects, toSearch){_x000D_
        var _finded=false;_x000D_
        for(var i=0; i<objects.length; i++) {_x000D_
            for(key in objects[i]) {_x000D_
                if(objects[i][key]!=null && typeof(objects[i][key] )!="boolean" && typeof(objects[i][key] )!="number"){_x000D_
                    if (typeof objects[i][key] == 'object') {_x000D_
                        _finded= searchInChild(objects[i][key],toSearch);_x000D_
_x000D_
                    }_x000D_
                    else if(objects[i][key].indexOf(toSearch)!=-1) {_x000D_
                        _finded=true;_x000D_
                    }_x000D_
                }_x000D_
            }_x000D_
        }_x000D_
        return _finded;_x000D_
    }_x000D_
    function findNested(objects, toSearch) {_x000D_
        var _results=[];_x000D_
        for(var i=0; i<objects.length; i++) {_x000D_
            for(key in objects[i]) {_x000D_
                if(objects[i][key]!=null && typeof(objects[i][key] )!="boolean" && typeof(objects[i][key] )!="number"){_x000D_
                    if (typeof objects[i][key] == 'object') {_x000D_
                        if(searchInChild(objects[i][key],toSearch)){_x000D_
                            _results.push(objects[i]);_x000D_
                        }_x000D_
                    }_x000D_
                    else if(objects[i][key].indexOf(toSearch)!=-1) {_x000D_
                        _results.push(objects[i]);_x000D_
                    }_x000D_
                }_x000D_
            }_x000D_
        }_x000D_
_x000D_
        return _results;_x000D_
_x000D_
    }_x000D_
    $('.quickSearch').on('click',function(){_x000D_
          var _inputSeach=$('#evertingSearch').val();_x000D_
          if(_inputSeach!=''){_x000D_
          var _finded=findNested(students,_inputSeach);_x000D_
          $('.count').html(_finded.length);}_x000D_
    _x000D_
    });
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>_x000D_
<html>_x000D_
<head>_x000D_
</head>_x000D_
<body>_x000D_
<span>_x000D_
<pre><code>_x000D_
       var students=[{name:"ali",family:"romandeh",age:18,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]},_x000D_
   {name:"hadi",family:"porkar",age:48,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]},_x000D_
   {name:"majid",family:"rezaeiye",age:30,curse:[_x000D_
   {lesson1:"arabic"},_x000D_
   {lesson2:"english"},_x000D_
   {lesson3:"history"}_x000D_
   ]}_x000D_
   ];_x000D_
</code></pre>_x000D_
_x000D_
<span>_x000D_
_x000D_
<input id="evertingSearch" placeholder="Search on students" />_x000D_
<input type="button" class="quickSearch" value="search" />_x000D_
<lable>count:</lable><span class="count"></span>_x000D_
_x000D_
_x000D_
</body>_x000D_
_x000D_
_x000D_
_x000D_
</html>
_x000D_
_x000D_
_x000D_


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; })

Came across this problem today and using a modified version of the provided code by epascarello in this thread 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);
   }
  })
 );
};

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' }]

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.


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.

_x000D_
_x000D_
//Search function_x000D_
var locateInObject = function(obj, key, find, result, currentLocation){_x000D_
  if(obj === null) return;_x000D_
  result = result||{done:[],found:{}};_x000D_
  if(typeof obj == 'object'){_x000D_
    result.done.push(obj);_x000D_
  }_x000D_
  currentLocation = currentLocation||key;_x000D_
  var keys = Object.keys(obj);_x000D_
  for(var k=0; k<keys.length; ++k){_x000D_
    var done = false;_x000D_
    for(var d=0; d<result.done.length; ++d){_x000D_
      if(result.done[d] === obj[keys[k]]){_x000D_
        done = true;_x000D_
        break;_x000D_
      }_x000D_
    }_x000D_
    if(!done){_x000D_
      var location = currentLocation+'.'+keys[k];_x000D_
      if(typeof obj[keys[k]] == 'object'){_x000D_
        locateInObject(obj[keys[k]], keys[k], find, result, location)_x000D_
      }else if((typeof find == 'string' && obj[keys[k]].toString().indexOf(find) > -1) || (typeof find == 'function' && find(obj[keys[k]], keys[k]))){_x000D_
        result.found[location] = obj[keys[k]];_x000D_
      }_x000D_
    }_x000D_
  }_x000D_
  return result.found;_x000D_
}_x000D_
_x000D_
//Test data_x000D_
var test = {_x000D_
  key1: {_x000D_
    keyA: 123,_x000D_
    keyB: "string"_x000D_
  },_x000D_
  key2: {_x000D_
    keyC: [_x000D_
      {_x000D_
        keyI: "string123",_x000D_
        keyII: 2.3_x000D_
      },_x000D_
      "string"_x000D_
    ],_x000D_
    keyD: null_x000D_
  },_x000D_
  key3: [_x000D_
    1,_x000D_
    2,_x000D_
    123,_x000D_
    "testString"_x000D_
  ],_x000D_
  key4: "123string"_x000D_
}_x000D_
//Add a circular reference_x000D_
test.key5 = test;_x000D_
_x000D_
//Tests_x000D_
console.log(locateInObject(test, 'test', 'string'))_x000D_
console.log(locateInObject(test, 'test', '123'))_x000D_
console.log(locateInObject(test, 'test', function(val, key){ return key.match(/key\d/) && val.indexOf('string') > -1}))
_x000D_
_x000D_
_x000D_


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

_x000D_
_x000D_
function filter(array, value, key) {_x000D_
    return array.filter(key_x000D_
        ? a => a[key] === value_x000D_
        : a => Object.keys(a).some(k => a[k] === value)_x000D_
    );_x000D_
}_x000D_
_x000D_
var a = [{ name: 'xyz', grade: 'x' }, { name: 'yaya', grade: 'x' }, { name: 'x', frade: 'd' }, { name: 'a', grade: 'b' }];_x000D_
_x000D_
_x000D_
console.log(filter(a, 'x'));_x000D_
console.log(filter(a, 'x', 'name'));
_x000D_
.as-console-wrapper { max-height: 100% !important; top: 0; }
_x000D_
_x000D_
_x000D_


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.

_x000D_
_x000D_
var a = [{_x000D_
  name: 'xyz',_x000D_
  grade: 'x'_x000D_
}, {_x000D_
  name: 'yaya',_x000D_
  grade: 'x'_x000D_
}, {_x000D_
  name: 'x',_x000D_
  frade: 'd'_x000D_
}, {_x000D_
  name: 'a',_x000D_
  grade: 'b'_x000D_
}];_x000D_
_x000D_
function filterIt(arr, searchKey) {_x000D_
  return arr.filter(function(obj) {_x000D_
    return Object.keys(obj).some(function(key) {_x000D_
      return obj[key].includes(searchKey);_x000D_
    })_x000D_
  });_x000D_
}_x000D_
_x000D_
console.log("find 'x'", filterIt(a,"x"));_x000D_
console.log("find 'a'", filterIt(a,"a"));_x000D_
console.log("find 'z'", filterIt(a,"z"));
_x000D_
_x000D_
_x000D_

Or with ES6

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

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" }]

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.


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.


MAKE SIMPLE

const objects = [
     {
     "foo" : "bar",
     "bar" : "sit",
     "date":"2020-12-20"
     },
     {
     "foo" : "lorem",
     "bar" : "ipsum",
     "date":"2018-07-02"
     },
     {
     "foo" : "dolor",
     "bar" : "amet",
     "date":"2003-10-08"
     },
     {
     "foo" : "lolor",
     "bar" : "amet",
     "date":"2003-10-08"
     }
     ];
     
     
     
     const filter = objects.filter(item => {
     const obj = Object.values(item)
     return obj.join("").indexOf('2003') !== -1
     })
     
     console.log(filter)

You can use the _filter method of lodash:

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

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

_x000D_
_x000D_
function search(arr, s){_x000D_
    var matches = [], i, key;_x000D_
    _x000D_
    for( i = arr.length; i--; )_x000D_
        for( key in arr[i] )_x000D_
            if( arr[i].hasOwnProperty(key) && arr[i][key].indexOf(s) > -1 )_x000D_
                matches.push( arr[i] );  // <-- This can be changed to anything_x000D_
_x000D_
    return matches;_x000D_
};_x000D_
_x000D_
// dummy data_x000D_
var items = [_x000D_
      {_x000D_
        "foo" : "bar",_x000D_
        "bar" : "sit"_x000D_
      },_x000D_
      {_x000D_
        "foo" : "lorem",_x000D_
        "bar" : "ipsum"_x000D_
      },_x000D_
      {_x000D_
        "foo" : "dolor",_x000D_
        "bar" : "amet"_x000D_
      }_x000D_
];_x000D_
    _x000D_
var result = search(items, 'lo'); // search "items" for a query value_x000D_
console.log(result); // print the result
_x000D_
_x000D_
_x000D_


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 through posts to find the word
posts.forEach((post) => {
    if (post["text_field"].match(regexp)) matches.push(post);
});

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to json

Use NSInteger as array index Uncaught SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) HTTP POST with Json on Body - Flutter/Dart Importing json file in TypeScript json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 190) Angular 5 Service to read local .json file How to import JSON File into a TypeScript file? Use Async/Await with Axios in React.js Uncaught SyntaxError: Unexpected token u in JSON at position 0 how to remove json object key and value.? Find a file by name in Visual Studio Code Search all the occurrences of a string in the entire project in Android Studio Java List.contains(Object with field value equal to x) Trigger an action after selection select2 How can I search for a commit message on GitHub? SQL search multiple values in same field Find a string by searching all tables in SQL Server Management Studio 2008 Search File And Find Exact Match And Print Line? Java - Search for files in a directory How to put a delay on AngularJS instant search?