Filter complex data structure

given a random data structure (maybe something is real):

const data = [
 {
  name: "John",
  age: 26,
  company: {
   name: "Some company",
   address: "Some address"
  }
 },{...}
];

      

I would like to be able to search in all object and helper object values. For example, if the user types in John, I would like to return all objects containing "John", and if the user searches for "Some company", I would like to return all objects containing abstracts.

I was thinking about flattening the ob structure of each object and then filtering the original list, but that somehow doesn't seem right. Any suggestions?

+3


source to share


3 answers


You can use recursive object search with Object.values

.



var data = [{ name: "John", age: 26, company: { name: "Some company", address: "Some address" } }, { name: "Jane", age: 32, company: { name: "Cameo", address: "2nd Root Dr" } }],
    find = 'Cameo',
    result = data.filter(o => Object.values(o).some(function search(v) {
        return v && typeof v === 'object' ? Object.values(v).some(search) : v === find;
    }));
  
console.log(result);
      

.as-console-wrapper { max-height: 100% !important; top: 0; }
      

Run codeHide result


+2


source


You can use the path to search, for example:

search(data, "name", "John"); // search for object with names equal to "John"
search(data, "company.adress", "some adress"); // search for objects with company adresses equal to "some adress"
// ...

      

The code for this would be:

function path2value(obj, path) {
    return path.split(".").reduce((o, p) => (o? o[p]: undefined), obj);
}

function search(arr, path, value) {
    return arr.filter(o => path2value(o, path) === value);
}

      

Example:

const data = [{
  name: "John",
  age: 26,
  company: {
    name: "Some company",
    address: "Some address"
  }
}, {
  name: "Ibrahim",
  age: 23,
  company: {
    name: "Some company",
    address: "Some address"
  }
}];

function path2value(obj, path) {
  return path.split(".").reduce((o, p) => (o ? o[p] : undefined), obj);
}

function search(arr, path, value) {
  return arr.filter(o => path2value(o, path) === value);
}

console.log(search(data, "name", "John"));
console.log(search(data, "company.name", "Some company"));
      

Run codeHide result


EDIT:



If you don't want to pass in path

and you want to filter the recursevly object. You can make a function that iterates over all the values ​​in the object and their subobjects and passes them to the callback (where you can specify whether or not this object is included), if the callback returns true then the root object will be included in the results array. otherwise it won't. The use of such a function would be as follows:

filterRecursive(data, value => value === "John"); // filter the objects by value equals to "John"
filterRecursive(data, value => typeof(value) === "number" && value > 20); // filter the objects by values that are numbers and greater than 20
filterRecursive(data, value => /^Some/.test(value)); // filter the objects with values that start with "Some"

      

the function would be:

function filterRecursive(arr, cb) {                                   // takes an array and a callback and recursively call the callback on each value in the object and sub object
    function hasIt(obj) {                                             // take an object and recurseively call the callback cb on its values and its subobjects values returning true if one of those values returned true, false if none of them returened true
        for(let key in obj) {                                         // for each key in the object
            if(obj.hasOwnProperty(key)) {                             // if the key is owned by this object
                if(Object.prototype.toString.call(obj[key]) === "[object Object]") {  // if the value on this key is another object...
                    if(hasIt(obj[key])) return true;                  // then call hasIt on it and if it returned true then return true and stop the search for this object
                }
                else if(cb(obj[key])) return true;                    // otherwise, if it not an object, then pass it to the callback, if the callback returned true, then return true and stop the search
            }
        }
        return false;                                                 // return false if the recursive search failed
    }

    return arr.filter(o => hasIt(o)); // filter the root object by whether they have it or not (hasIt)
}

      

Example:

function filterRecursive(arr, cb) {
  function hasIt(obj) {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (Object.prototype.toString.call(obj[key]) === "[object Object]") {
          if (hasIt(obj[key])) return true;
        } else if (cb(obj[key])) return true;
      }
    }
    return false;
  }

  return arr.filter(o => hasIt(o));
}

const data = [{
  name: "John",
  age: 26,
  company: {
    name: "Some company",
    address: "Some address"
  }
}, {
  name: "Ibrahim",
  age: 23,
  company: {
    name: "Some company",
    address: "Some address"
  }
}];

console.log(filterRecursive(data, v => v === "John"));
console.log(filterRecursive(data, v => /^Some/.test(v)));
      

Run codeHide result


+2


source


You can try something like this:

function getObjectValues(obj, values){
  for(var key in obj){
    let value = obj[key];
    if(typeof value === "object"){
      getObjectValues(value, values);
    } else {
        values.push(value)
    }
  }
  return values;
}
    
const data = [ 
 {
  name: "John",
  age: 26,
  company: {
   name: "Some company",
   address: "Some address"
  }
},
{
  name: "Bar",
  age: 27,
  company: {
   name: "Some company",
   address: "Some address"
  }
},
{
  name: "Foo",
  age: 28,
  company: {
   name: "Some company John",
   address: "Some address"
  }
}];

let filteredData = data.filter(function(obj){
    return getObjectValues(obj,[]).some(function(value){
        return value.toString()
                    .includes("John");
    });
});


console.log(filteredData);
      

Run codeHide result


0


source







All Articles