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

6

我有一个对象数组,想要通过比较嵌套属性和搜索词来进行筛选。

例如:

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

谢谢您。
6个回答

10
你可以使用Array#filter方法,并通过使用Array#some查看嵌套数组。
如果在嵌套数组中找到标签,则迭代停止并将结果返回给过滤器回调函数。请保留HTML标记。

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


1
如果我想要比较两个值怎么办? - nicogaldo
@nicogaldo 将最后一个 tagt.tag 交换以启用多个比较。 - Steven Mcsorley

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


这是一个很好的回答,Roman,谢谢你。我选择了Nina的回答,因为她的回答更加简洁,并且先被添加。干得好。 - slotdp02

1

试试这个:

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

所以:
console.log(search('market'));

我希望能对你有所帮助:)

这也会搜索关键字,所以如果你搜索“标签”,你会发现每个对象都匹配。 - Heretic Monkey

1

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

0
你可以这样使用 array.filter
function getFiltered(val) {
     return array.filter(category == val);
}

此函数将返回一个新的数组实例,只包含你作为参数传递的 category 键。


0
注意:我正在采用一种快捷方式的方法来处理这个问题,主要是为了提供一个不同的视角。
相比于深度搜索主要的 array 下的属性和数组,你可以创建一个 json 字符串的 users 属性,并在其中进行搜索。因此,我创建了一个新属性 usersString ,它临时存储了针对 users 属性的值的 JSON 字符串。
item.usersString = JSON.stringify(item.users);

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接