简体   繁体   English

通过搜索嵌套对象属性来过滤对象数组

[英]Filtering array of objects by searching nested object properties

I have an array of objects that I want to filter by comparing a nested property to a search term. 我有一个对象数组,我想通过比较嵌套属性和搜索词来过滤。

For example: 例如:

 var array = [
      {category: 'Business'
       users: [
                {name: 'Sally'
                 tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
                },
                {name: 'Bob'
                 tags: [{tag: 'sales'}, {tag: 'accounting'},...]
                }...
              ]
       },
       {category: 'Heritage'
        users: [
                 {name: 'Linda'
                  tags: [{tag: 'Italy'}, {tag: 'Macedonia'},...]
                 },
                 {name: 'George'
                  tags: [{tag: 'South Africa'}, {tag: 'Chile'},...]
                 },...
               ]
       },...
    [

Essentially I want to filter the base array of objects by a search terms that include characters from the tag property string in the nested objects 2 arrays down. 基本上我想通过搜索项过滤对象的基础数组,搜索项包括嵌套对象2数组中的标记属性字符串中的字符。

So a search for 'market' would result in 因此,搜索“市场”将导致

[
  {category: 'Business'
   users: [
            {name: 'Sally'
             tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
            },
            {name: 'Bob'
             tags: [{tag: 'sales'}, {tag: 'accounting'},...]
            }...
          ]
   }
]

Thank you. 谢谢。

You could use Array#filter with looking into the nested arrays by using Array#some . 您可以使用Array#filter通过使用Array#some查看嵌套数组。

If the tag is found in a nested array, then iteration stops and the result is given back to the filter callback. 如果在嵌套数组中找到标记,则迭代停止并将结果返回给过滤器回调。

 var array = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }], tag = 'marketing', result = array.filter(a => a.users.some(u => u.tags.some(t => t.tag.includes(tag)))); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Try this: 尝试这个:

function search(term){
return
    Array.filter(array,function(item){
       return JSON.stringify(obj).indexOf(term)!=-1;
    });
}

So : 所以:

console.log(search('market'));

I hope to be helpful for you:) 我希望对你有所帮助:)

The solution using Array.prototype.some() function: 使用Array.prototype.some()函数的解决方案:

 var arr = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }], search_key = 'market', result = []; arr.forEach(function(o){ if (o.users.some(function(v){ return v.tags.some(function(i){ return i.tag.indexOf(search_key) !== -1; }); })) { result.push(o); } }); console.log(result); 

The concatAll and concatMap definitions are taken from http://reactivex.io/learnrx/ concatAllconcatMap定义取自http://reactivex.io/learnrx/

Array.prototype.concatAll = function() {
    var results = [];
    this.forEach(function(subArray) {
        results.push.apply(results, subArray);
    });

    return results;
};

Array.prototype.concatMap = function(projectionFunctionThatReturnsArray) {
    return this.
        map(function(item) {
            return projectionFunctionThatReturnsArray(item);
        }).
        // apply the concatAll function to flatten the two-dimensional array
        concatAll();
};

function filterByTags(keyword) {
  return array.filter(function (item) {
    var allTags = item.users.concatMap(function (user) {
      return user.tags.map(function (tag) {
        return tag.tag;
      });
    });

    return allTags.some(function (tag) {
      return tag.indexOf(keyword) > -1;
    });
  });
}

console.log(filterByTags('market'));

Of course you could inline the allTags variable for more conciseness. 当然,您可以内联allTags变量以获得更简洁。

The filter applied to the initial array will return all items that have users whose tags contain the keyword supplied. 应用于初始数组的filter将返回所有具有标记包含所提供关键字的用户的项目。 The strategy is to build a flattened version of the users' tags and apply some on that. 策略是构建用户标签的扁平版本并在其上应用some

You can use array.filter like this: 您可以像这样使用array.filter

function getFiltered(val) {
     return array.filter(category == val);
}

This function will return a new array instance, only with the category keys you passed as the val params. 此函数将返回一个新的数组实例,仅使用作为val参数传递的category键。

Note: I am taking a shortcut-like approach to this, primarily to provide a different perspective to the problem. 注意:我采用类似快捷方式的方法,主要是为问题提供不同的视角。

Instead of deep-searching the properties and arrays under the main array , you can create a json string of the users property and search within that. 您可以创建users属性的json字符串并在其中进行搜索,而不是深入搜索主array下的属性和数组。 So I have created a new property usersString that temporarily stores the JSON string of the value against users property. 所以我创建了一个新属性usersString ,它临时存储了针对users属性的值的JSON字符串。

item.usersString = JSON.stringify(item.users);

Now, this would not be a perfect implementation, but it would almost always work. 现在,这不是一个完美的实现,但它几乎总是有效。 Also, if you stored this property within the browser (without storing it back to the DB), and used it to quick-search for every time user searches, I think it would be more performant that deep-searching entire array. 此外,如果您将此属性存储在浏览器中(不将其存储回数据库),并在每次用户搜索时使用它来快速搜索,我认为深度搜索整个数组会更有效。

 var array = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] } ] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] } ] } ]; var key = "market"; // Convert the users property into a string - so that it works as a quick search target. array.forEach(function(item) { item.usersString = JSON.stringify(item.users); }); var filteredItems = array.filter(function(item) { return item.usersString.toLowerCase().indexOf(key.toLowerCase()) >= 0; }); // Delete the usersString property - if required. filteredItems.forEach(function(item) { item.usersString = undefined; // Or, // delete item.usersString; }) console.log(filteredItems); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM