如何基于嵌套数组中的值检索正确的父对象

时间:2019-07-14 12:23:34

标签: javascript arrays loops

我有一个具有以下结构的对象数组:

var items = [
  {
    itemId: 0,
    itemQuantity: 10,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "Black" }
    ]
  },
  {
    itemId: 1,
    itemQuantity: 20,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "White" }
    ]
  },
  {
    itemId: 2,
    itemQuantity: 30,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "Black" }
    ]
  },
  {
    itemId: 3,
    itemQuantity: 40,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "White" }
    ]
  }
];

我还有一个基本数组,其中包含以下值

let selectedAttributes = ["Small", "Black"];

我的目标是基于嵌套数组(attributes)中的值获取父级对象。要详细说明,我需要使用嵌套数组(selectedAttributes)中的value属性检查attributes数组中的值。这意味着,我需要检索包含两者值“ Small”和“ Black”的对象。这应该是它的结果:

let result = [
  {
    itemId: 0,
    itemQuantity: 10,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "Black" }
    ]
  }
]

下面是我当前的代码。当我处理结果时,我得到了一个空数组

let result = items.filter((item, index) => {
  return item.attributes.some(attri => attri.value === selectedAttributes);
});

console.log(result);

1 个答案:

答案 0 :(得分:1)

您只检查第一个匹配对象的value(因为您正在使用.some),而不检查其他对象。相反,您想使用value检查每个对象的每个.includes属性是否是属性列表中的一个属性:

var items = [
  {
    itemId: 0,
    itemQuantity: 10,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "Black" },
    ]
  },
  {
    itemId: 1,
    itemQuantity: 20,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "White" }
    ]
  },
  {
    itemId: 2,
    itemQuantity: 30,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "Black" }
    ]
  },
  {
    itemId: 3,
    itemQuantity: 40,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "White" }
    ]
  }
];

const selectedAttributes = ["Small", "Black"];
const res = items.filter((item, index) => {
  return item.attributes.every(attri => selectedAttributes.includes(attri.value));
});

console.log(res);

如果只需要对象(而不是对象数组),则可以使用.find()代替filter()。一旦内部函数返回.find()true就会停止:

var items = [
  {
    itemId: 0,
    itemQuantity: 10,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "Black" },
    ]
  },
  {
    itemId: 1,
    itemQuantity: 20,
    attributes: [
      { type: "Size", value: "Small" },
      { type: "Color", value: "White" }
    ]
  },
  {
    itemId: 2,
    itemQuantity: 30,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "Black" }
    ]
  },
  {
    itemId: 3,
    itemQuantity: 40,
    attributes: [
      { type: "Size", value: "Medium" },
      { type: "Color", value: "White" }
    ]
  }
];

const selectedAttributes = ["Small", "Black"];
const res = items.find((item, index) => {
  return item.attributes.every(attri => selectedAttributes.includes(attri.value));
});

console.log(res);


请注意,如果所有属性对象都与提供的列表中的属性匹配,则上述解决方案将起作用。如果要使对象中的属性可以具有其他属性以及属性列表的那些部分,则需要在属性列表上使用.every,而不要像这样使用对象属性:

var items = [{
    itemId: 0,
    itemQuantity: 10,
    attrs: [{
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "Black"
      },
      {
        type: "John",
        value: "Name"
      }
    ]
  },
  {
    itemId: 1,
    itemQuantity: 20,
    attrs: [{
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  },
  {
    itemId: 2,
    itemQuantity: 30,
    attrs: [{
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    itemId: 3,
    itemQuantity: 40,
    attrs: [{
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  }
];

const attrs = ["Small", "Black"];
const res = items.filter((item, index) => {
	const values = item.attrs.map(o => o.value);
  return attrs.every(attri => values.includes(attri));
});

console.log(res);