过滤复杂的数据结构



给定一个随机数据架构(实际上可以是任何东西(:

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

我希望能够在对象和子对象的所有值中搜索。例如,如果用户在John中类型类型,我想返回包含" John"的所有对象,如果用户搜索"某些公司",我也想返回包含本文的所有对象。

我正在考虑将结构弄平每个对象,然后过滤原始列表,但这并不是正确的。有任何建议吗?

您可以使用 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; }

您可以使用搜索路径,例如:

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"
// ...

代码将是:

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

示例:

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

编辑:

如果您不想传递path并且要过滤对象recursevly。您可以制作一个函数,以跨越对象中的所有值及其子对象,然后将它们传递给回调(您可以在其中指定是否包含该对象(,如果回调返回true,则将包含root对象在结果数组中,否则不会。此类功能的使用将如下:

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"

该功能将是:

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's 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)
}

示例:

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

您可以尝试这样的事情:

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

最新更新