【问题标题】:Filter object by tag (array inside an array of objects)按标签过滤对象(对象数组中的数组)
【发布时间】:2019-01-04 23:48:39
【问题描述】:

目标

编辑 - 使问题更清晰

创建可根据项目标签缩小搜索结果范围并仅返回具有指定标签的项目的搜索。 示例: ['green'] 将给我所有绿色的项目,包括大、中和小(因为没有指定尺寸),['green','big'] 将只给我绿色和大的项目。

我遇到了一个场景。为了简化事情,我有以下数据

items: [
    { title: 'prod1', tags: [{ value: 'green' }, { value: 'big' }] },
    { title: 'prod2', tags: [{ value: 'blue' }, { value: 'small' }] },
    { title: 'prod3', tags: [{ value: 'yellow' }, { value: 'medium' }, { value: 'big' }] },
    { title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },
]

我的搜索字段是一个多选输入,带有预定义的标签(如本网站中的标签字段) 该字段的值作为数组输出。如果我选择green,则输出为 ['green'] 如果我选择 greenbig 它输出 ['green', 'big']

如果我选择标签green 我应该得到这些结果

{ title: 'prod1', tags: [{ value: 'green' }, { value: 'big' }] },
{ title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },

如果我选择标签 greenmedium 我会得到这些结果,因为 prod4 是唯一一个带有标签 green 和 medium 的标签

{ title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },

如果我选择 greenbig 我应该得到

{ title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },
{ title: 'prod1', tags: [{ value: 'green' }, { value: 'big' }] }

如果没有选择,则输出所有项目


原始问题

I ran into a scenario. To simplify things, i have the following data

items: [
  {title: 'one', desc: 'this is one', tags: [{value: 'mytag'},{value: 'one'}]},
  {title: 'two', desc: 'this is two', tags: [{value: 'mytag'},{value: two}]},
  {title: 'three', desc: 'this is three', tags: [{value: 'mytag'},{value: 'three'},{value: 'common'}]},
  {title: 'four', desc: 'this is four', tags: [{value: 'mytag'},{value: 'four'},{value: 'common'}]},
]

我有一个接受标签的搜索输入元素,输入的值是一个数组。输入的值为['tag','two'] 我似乎无法弄清楚如何按标签过滤我的项目。

如果我按标签二(['two'])搜索,我应该得到一个返回

filteredItems: [
   {title: 'two', desc: 'this is two', tags: [{value: 'mytag'},{value: two}]},
]

如果我搜索两个,常见的 (['two','common']) 我应该得到一个返回

filteredItems: [
  {title: 'three', desc: 'this is three', tags: [{value: 'mytag'},{value: 'three'},{value: 'common'}]},
  {title: 'four', desc: 'this is four', tags: [{value: 'mytag'},{value: 'four'},{value: 'common'}]},
]

我尝试查看一些示例,发现一些仅过滤顶级项目而不是嵌套数组的示例。

谢谢 :) 顺便用javascript,可以用lodash。

我的游乐场 JS 文件:

const _ = require('lodash')

let items = [
    {
        name: 'hello',
        tags: [
            { value: 1 },
            { value: 2 },
        ]
    },
    {
        name: 'bye',
        tags: [
            { value: 2 },
            { value: 4 },
        ]
    }
]
items.map(item =>{

    let test = _.includes(item.tags, 2)
    console.log(test)
// returns false, false
})

【问题讨论】:

  • 为什么搜索['two','common']不包括two对象?
  • 这是搜索下拉列表(使用语义 ui)列表吐出其值的方式.. 带有字符串数组..
  • 在第一个代码块中,您没有使用字符串文字'two',而是使用该名称的变量。
  • 所以?不管格式如何,为什么在搜索two 时没有匹配到two 对象?我没听懂
  • two 的值是多少?你在哪里定义它?

标签: javascript arrays object filter


【解决方案1】:

(注意:此答案的第一部分与编辑之前的原始问题有关)

你需要更深一层。您的最终 playground 代码是将对象与 2 进行比较,但您应该将对象 property 与 2 进行比较。

let test = items.filter(item =>{
    return item.tags.some(obj => obj.value === 2)
})

或者,如果要查找的值在其他属性中:

let test = items.filter(item =>{
    return item.tags.some(obj => obj.text === 'two')
})

修改您的问题后

您的示例数据可以这样搜索:

function search(items, constraints) {
    return items.filter(item =>
        constraints.every(constraint => 
            item.tags.some(obj => obj.value === constraint)
        )
    );
}

const items = [
    { title: 'prod1', tags: [{ value: 'green' }, { value: 'big' }] },
    { title: 'prod2', tags: [{ value: 'blue' }, { value: 'small' }] },
    { title: 'prod3', tags: [{ value: 'yellow' }, { value: 'medium' }, { value: 'big' }] },
    { title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },
];

console.log(search(items, ["green", "medium"]));

您需要的逻辑是 AND 和 OR 逻辑的组合:对于匹配给定约束的数组元素,它应该有 some 匹配对象 (OR) 用于 every 给定约束中的值 (AND)。

【讨论】:

  • 是的,这行得通.. 至少对于我的游乐场测试.. 但是,我仍在尝试找出解决我原来的问题的解决方案,即使用数组进行搜索/过滤。
  • 添加了如何将其应用于您的原始问题。
  • 越来越近了.. 而不是“两个”或“普通”,它必须是“两个”和“普通”。我用更多信息更新了我的问题,可能会更清楚。我尝试在 .some 函数中使用 indexOf 来返回任何!== -1,并且仅在搜索单个标签时才有效。但是一旦我添加了第二个标签(['tag1','tag2']),我什么也得不到。顺便说一句,非常感谢你,我觉得我离我越来越近了。
  • 这取决于:如果您需要所有条件(在输入数组中提供)对于一个匹配项都为真,那么您需要 every (但是您的问题中的示例更加错误:那里没有both“two”和“common”的记录)。另一方面,如果匹配具有输入中提供的至少一个值就足够了,那么您需要some。但是,您的 ["two", "common"] 示例应该给出 3 个结果而不是 2 个。如果您可以使您的问题更清楚和一致地说明您在该示例中需要什么,我会相应地更新我的答案。
  • 那里,我更新了问题。我很抱歉。我不是很清楚。
【解决方案2】:

感谢来自 martinoss 的post

解决方案:

使用 lodash 过滤功能

let filteredItems = _.filter(items, {tags: [{value: 'green'},{value: 'big'}]}
console.log(filteredItems)

// { title: 'prod1', tags: [{ value: 'green' }, { value: 'big' }] },
// { title: 'prod4', tags: [{ value: 'green' }, { value: 'big' }, { value: 'medium' }] },

这将只返回具有两个标签(绿色和大)的对象。

我确实必须修改数组并将其转换为对象(我的选择将值输出为 ['green','big']

我通过以下方式做到了这一点:

let search = ['green', 'big']

search = search.map(searchTag => {
    return {value: searchTag}
})

// [{value: 'green'},{value: 'big'}]

如果有香草 es6 的方式,我很乐意看到它.. 现在这对我有用

【讨论】:

    【解决方案3】:

    下面的代码应该完成你想要的,如果搜索中的约束变量为 null、未定义、''、[] 或未提供,则返回项目而不进行过滤。如果约束变量是字符串,则假设是一个应用于返回的项目的约束,如果约束是数组,则应用所有约束。我试图以一种不言自明的方式命名变量。

    var search = (items, constraints) => {
        //no constraints supplied, null, undefined, '', or empty array
      if ( !constraints || constraints === '' || (Array.isArray(constraints) && constraints.length === 0) ) {
        return items;
      }
    
      let match = false;
      let cons = [];
    
      //constraints is a string with one constraint add it to an array
      if (typeof constraints === 'string') {
        cons.push(constraints);
      }
    
      //if constraints is an array of constraints 1 or more
      if (Array.isArray(constraints)) {
        cons.concat(constraints);
        return items.filter( (item) => {
          match = true;
          let itemTags = item.tags.map( (tag) => tag.value );
          cons.forEach( (constraint) => {
            if (constraint === '') return;
            match = (itemTags.indexOf(constraint) > -1 && match);
          } );
          return match;
        } );
    
      }
    
    };
    

    【讨论】:

      猜你喜欢
      • 2018-11-12
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多