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

Posted

技术标签:

【中文标题】通过搜索嵌套对象属性过滤对象数组【英文标题】:Filtering array of objects by searching nested object properties 【发布时间】:2018-01-16 10:05:27 【问题描述】:

我有一个对象数组,我想通过将嵌套属性与搜索词进行比较来过滤它们。

例如:

 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',...]
                 ,...
               ]
       ,...
    [

本质上,我想通过搜索项过滤对象的基本数组,其中包括嵌套对象 2 个数组中标签属性字符串中的字符。

所以搜索“市场”会导致

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

谢谢。

【问题讨论】:

【参考方案1】:

您可以使用Array#filter 通过Array#some 查看嵌套数组。

如果在嵌套数组中找到标记,则迭代停止并将结果返回给过滤器回调。

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; 

【讨论】:

如果我想比较两个值?【参考方案2】:

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

【讨论】:

这是一个很好的答案罗马,谢谢。我刚刚接受了 Nina 的,因为首先添加了她的并且更简洁一些。干得好。【参考方案3】:

试试这个:

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

所以:

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

希望对你有帮助:)

【讨论】:

这也会搜索键,所以如果你搜索“tag”,你会发现每个对象都匹配。【参考方案4】:

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

当然,您可以内联 allTags 变量以获得更简洁。

应用于初始数组的filter 将返回其标签包含所提供关键字的用户的所有项目。策略是构建用户标签的扁平化版本并在其上应用some

【讨论】:

【参考方案5】:

你可以像这样使用array.filter

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

此函数将返回一个新的数组实例,仅使用您作为 val 参数传递的 category 键。

【讨论】:

【参考方案6】:

注意:我对此采取了类似捷径的方法,主要是为了提供不同的视角来解决问题。

您可以创建 users 属性的 json 字符串并在其中搜索,而不是深入搜索主 array 下的属性和数组。因此,我创建了一个新属性 usersString,该属性临时存储针对 users 属性的值的 JSON 字符串。

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

现在,这不是一个完美的实现,但它几乎总是可以工作的。此外,如果您将此属性存储在浏览器中(而不将其存储回数据库),并在每次用户搜索时使用它来快速搜索,我认为它会比深度搜索整个数组更高效。

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

【讨论】:

以上是关于通过搜索嵌套对象属性过滤对象数组的主要内容,如果未能解决你的问题,请参考以下文章

typescript 通过嵌套数组值过滤对象数组

Javascript通过包含搜索词的标签子数组过滤或减少每个JSON对象

递归过滤/减少嵌套对象

通过嵌套对象的属性修改嵌套对象的数组

如何通过嵌套对象属性对 JavaScript 对象数组进行排序?

markdown 使用ramda通过嵌套值过滤对象数组:有时您无权访问后端,并且您希望过滤来自