nfl-x
nfl-x

Reputation: 497

Filtering Array of Objects Recursively

I have these data structure

products:[
      {
        products_number: 14,
        products_ID: 'lvs_jeans-man',
        products_seller: 'a',
        products_SKU: [
          {
            productSKU_ID: 'nfl_lvs_jeans-man_xl_bl-stripe',
            productSKU_size: 'XL',
            productSKU_color: 'Blue_White'
          },
          {
            productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
            productSKU_size: 'XL',
            productSKU_color: 'Black'
          }
        ]
      },
      {
      products_number: 15,
      products_ID: 'lvs_jeans-man',
      products_seller: 'b',
      products_SKU: [
        {
          productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
          productSKU_size: 'XL',
          productSKU_color: 'Black'
        }
      ]
    },
    {
      products_number: 16,
      products_ID: 'lvs_jeans-man',
      products_seller: 'c',
      products_SKU: [
        {
          productSKU_ID: 'nfl_lvs_jeans-man_xl_gy',
          productSKU_size: 'XL',
          productSKU_color: 'Grey',

        }
      ]
    }
  ]

The constant

  var id = 'lvs_jeans-man'
  var size = 'XL'
  var color = 'Black'

How do i filter items that met these condition

products_ID == id
productSKU_color == color
productSKU_size == size

The needed output is

  [{
    products_number: 14,
    products_ID: 'lvs_jeans-man',
    products_seller: 'a',
    productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
  },
  {
    products_number: 15,
    products_ID: 'lvs_jeans-man',
    products_seller: 'b',
    productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
  }]

What i have tried is filter the products_ID first then filter the color and size so i can get the productSKU_ID inside and then just play around with array push, but it return Cannot read property 'filter' of undefined"

var temp1 =  this.products.filter((product => product.products_ID === this.id).products_SKU.filter(sku => (sku.productSKU_color === this.color && sku.productSKU_size === this.size)))

How to achieve the needed output?

Upvotes: 0

Views: 123

Answers (4)

Ele
Ele

Reputation: 33726

The function filter is not suitable because you need to build a custom output with data from the array .products_SKU.

Use this alternative using the functions reduce and find.

var data = {  products: [{      products_number: 14,      products_ID: 'lvs_jeans-man',      products_seller: 'a',      products_SKU: [{          productSKU_ID: 'nfl_lvs_jeans-man_xl_bl-stripe',          productSKU_size: 'XL',          productSKU_color: 'Blue_White'        },        {          productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',          productSKU_size: 'XL',          productSKU_color: 'Black'        }      ]    },    {      products_number: 15,      products_ID: 'lvs_jeans-man',      products_seller: 'b',      products_SKU: [{        productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',        productSKU_size: 'XL',        productSKU_color: 'Black'      }]    },    {      products_number: 16,      products_ID: 'lvs_jeans-man',      products_seller: 'c',      products_SKU: [{        productSKU_ID: 'nfl_lvs_jeans-man_xl_gy',        productSKU_size: 'XL',        productSKU_color: 'Grey',      }]    }  ]};

var id = 'lvs_jeans-man'
var size = 'XL'
var color = 'Black'

var result = data.products.reduce((a, p) => {
  var found;
  if (p.products_ID == id && (found = p.products_SKU.find(s => s.productSKU_size === size && s.productSKU_color === color))) {

    a.push({
      products_number: p.products_number,
      products_ID: p.products_ID,
      products_seller: p.products_seller,
      productSKU_ID: found.productSKU_ID
    });
  }

  return a;
}, []);

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Rushikesh Bharad
Rushikesh Bharad

Reputation: 1010

const finalProducts = this.products.reduce((final, product) =>  {
  if (product.id === this.id || !this.id) {
    return[...final, ...product.products_SKU.reduce((acc, p) => {
      if (p.productSKU_size === this.size && p.productSKU_color === this.color) {
        return [...acc, {
          products_number: product.products_number,
          products_ID: product.products_ID,
          products_seller: product.products_seller,
          productSKU_ID: p.productSKU_ID
        }];
      }
      return acc;
    }, [])];
  }
  return final;
}, []);

finalProducs will be your expected output.

Upvotes: 0

HMR
HMR

Reputation: 39280

You can filter by id first and then map products with first found productSKU, take out the products with undefined productSKU and map that to a result type:

const products = [
  {
    products_number: 14,
    products_ID: 'lvs_jeans-man',
    products_seller: 'a',
    products_SKU: [
      {
        productSKU_ID: 'nfl_lvs_jeans-man_xl_bl-stripe',
        productSKU_size: 'XL',
        productSKU_color: 'Blue_White'
      },
      {
        productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
        productSKU_size: 'XL',
        productSKU_color: 'Black'
      }
    ]
  },
  {
    products_number: 15,
    products_ID: 'lvs_jeans-man',
    products_seller: 'b',
    products_SKU: [
      {
        productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
        productSKU_size: 'XL',
        productSKU_color: 'Black'
      }
    ]
  },
  {
    products_number: 16,
    products_ID: 'lvs_jeans-man',
    products_seller: 'c',
    products_SKU: [
      {
        productSKU_ID: 'nfl_lvs_jeans-man_xl_gy',
        productSKU_size: 'XL',
        productSKU_color: 'Grey',

      }
    ]
  }
];

const filterProducts = products => (id,size,color) =>
  products.filter(//filter by id first
    product=>product.products_ID===id
  )
  .map(//map to products with filtered productSKU
    product=>({
      ...product,
      products_SKU: product.products_SKU.find(
        info=>
          info.productSKU_size===size &&
          info.productSKU_color===color
      )
    })
  )
  .filter(//take out empty products_SKU
    product=>
      product.products_SKU!==undefined
  );

const mapToResult = product => ({
  products_number: product.products_number,
  products_ID: product.products_ID,
  products_seller: product.products_seller,
  productSKU_ID: product.products_SKU.productSKU_ID
});

console.log(
  filterProducts(products)("lvs_jeans-man","XL","Black")
  .map(mapToResult)
);

Update

const myFunction = arg => otherArg => 22

Is a function that returns a function, without the arrow syntax it would look like this:

function myFunction(arg){
  return function(otherArg){return 22; }
}

In the filterProducts you can use it to have filter linked to a set of products, for example:

const filterPants = filterProducts(products.filter(pantsOnly))

The optimized answer from Ele would look like this:

var result = data.products.reduce((a, p) => {
  if (p.products_ID == id) {
    //only check found if id matches
    const found = p.products_SKU.find(
      s => s.productSKU_size === size && s.productSKU_color === color
    );
    if(!found){
      return a;//early return
    }
    a.push({
      products_number: p.products_number,
      products_ID: p.products_ID,
      products_seller: p.products_seller,
      productSKU_ID: found.productSKU_ID
    })
  }

  return a;
}, []);

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370949

It's too complicated for filter alone, you'll have to use more array methods, including reduce and find:

const input = {
  products: [{
      products_number: 14,
      products_ID: 'lvs_jeans-man',
      products_seller: 'a',
      products_SKU: [{
          productSKU_ID: 'nfl_lvs_jeans-man_xl_bl-stripe',
          productSKU_size: 'XL',
          productSKU_color: 'Blue_White'
        },
        {
          productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
          productSKU_size: 'XL',
          productSKU_color: 'Black'
        }
      ]
    },
    {
      products_number: 15,
      products_ID: 'lvs_jeans-man',
      products_seller: 'b',
      products_SKU: [{
        productSKU_ID: 'nfl_lvs_jeans-man_xl_bk',
        productSKU_size: 'XL',
        productSKU_color: 'Black'
      }]
    },
    {
      products_number: 16,
      products_ID: 'lvs_jeans-man',
      products_seller: 'c',
      products_SKU: [{
        productSKU_ID: 'nfl_lvs_jeans-man_xl_gy',
        productSKU_size: 'XL',
        productSKU_color: 'Grey',

      }]
    }
  ]
};

const matchingProducts = input.products.filter(({ products_ID }) => products_ID === 'lvs_jeans-man');
const output = matchingProducts.reduce((matches, product) => {
  const foundSizeObj = product.products_SKU.find(({ productSKU_color, productSKU_size }) => {
    return productSKU_size === 'XL' && productSKU_color === 'Black';
  });
  if (!foundSizeObj) return matches;
  const match = {...product};
  delete match.products_SKU;
  match.productSKU_ID = foundSizeObj.productSKU_ID;
  matches.push(match);
  return matches;
}, []);
console.log(output);

Upvotes: 0

Related Questions