Home > Software design >  JS push object with dynamic keys and values to an array
JS push object with dynamic keys and values to an array

Time:03-18

I have an array of objects with dynamic keys and values (so not all objects have category_id, size and so on) but I simplified it to this:

let products_row = [
  {
    id: 1,
    category_id: 11,
    options: {
      'modelName1': {
        size: '2 feet',
        colour: 'red',
        is_new: true
      },
      'modelName2': {
        size: '4 feet',
        colour: 'black',
        is_new: true
      },
    }
  },
  {
    id: 2,
    category_id: 21,
    options: {
      'modelName11': {
        size: '2 feet',
        colour: 'white',
        is_new: false
      },
      'modelName12': {
        size: '4 feet',
        colour: 'white',
        is_new: false
      },
    }
  },
  {
    id: 3,
    category_id: 31,
    options: {
      'modelName21': {
        size: '8 feet',
        colour: 'white',
        is_new: false
      },
      'modelName22': {
        size: '4 feet',
        colour: 'black',
        is_new: true
      },
    }
  },
  {
    id: 4,
    category_id: 41,
    options: {
      'modelName31': {
        size: '8 feet',
        colour: 'red',
        is_new: true
      },
      'modelName32': {
        size: '8 feet',
        colour: 'red',
        is_new: true
      },
    }
  }
]

the result data structure needs to be like this:

let resultArray = [
  {
        id: 1,
        category_id: 11,
        model: 'modelName1',
        size: '2 feet',
        colour: 'red',
        is_new: true
  },
  {
        id: 1,
        category_id: 11,
        model: 'modelName2',
        size: '4 feet',
        colour: 'black',
        is_new: true
  },
  {
        id: 2,
        category_id: 21,
        model: 'modelName11',
        size: '2 feet',
        colour: 'white',
        is_new: false
 },
 {
        id: 2,
        category_id: 21,
        model: 'modelName12',
        size: '4 feet',
        colour: 'white',
        is_new: false
  },
  {
        id: 3,
        category_id: 31,
        model: 'modelName21',
        size: '8 feet',
        colour: 'white',
        is_new: false
  },
  {
        id: 3,
        category_id: 31,
        model: 'modelName22',
        size: '4 feet',
        colour: 'black',
        is_new: true
  },
  {
        id: 4,
        category_id: 41,
        model: 'modelName31',
        size: '8 feet',
        colour: 'red',
        is_new: true
  },
  {
        id: 4,
        category_id: 41,
        model: 'modelName32',
        size: '8 feet',
        colour: 'red',
        is_new: true
  },
]

This is what I have tried:

let productsData = [];

products_row
.map((product, p) => Object.entries(product.options || {})
.filter((model, i) => {            
    return productsData.push(
      {
        model: model[0],          
        [Object.keys(product).filter(el => delete product.options)[i]]: Object.values(product)[i],
        [Object.keys(model[1] || [])[i]]: Object.values(model[1] || [])[i],
      }
    )
})
)

console.log(productsData)

But it returns not all data, which is expected because I can't figure out how to keep previous key-values:

[
  {      
        model: 'modelName1',
        id: 1,
        size: '2 feet',
  },
  {      
        model: 'modelName2',  
        category_id: 11,     
        colour: 'black',        
  },
  {     
        model: 'modelName11',
        id: 2,
        size: '2 feet',
 },
 {        
        model: 'modelName12',
        category_id: 21,
        colour: 'white',
  },
  {        
        model: 'modelName21',
        id: 3,
        size: '8 feet',
  },
  {        
        model: 'modelName22',
        category_id: 31,
        colour: 'black',
  },
  {        
        model: 'modelName31',
        id: 4,
        size: '8 feet',
  },
  {        
        model: 'modelName32',
        category_id: 41,
        colour: 'red',
  },
]

I am completely stuck, any help is appreciated. Thank you.

CodePudding user response:

you can use flatMap and map
What flatMap does is if the returned array of map looks like

[
[{...1},{...2}],
[{...3},{...4}]
]

it will flatten it and give

[
{...1},{...2},
{...3},{...4}
]

let products_row = [{id: 1,category_id: 11,options: {'modelName1': {size: '2 feet',colour: 'red',is_new: true},'modelName2': {size: '4 feet',colour: 'black',is_new: true},}},{id: 2,category_id: 21,options: {'modelName11': {size: '2 feet',colour: 'white',is_new: false},'modelName12': {size: '4 feet',colour: 'white',is_new: false},}},{id: 3,category_id: 31,options: {'modelName21': {size: '8 feet',colour: 'white',is_new: false},'modelName22': {size: '4 feet',colour: 'black',is_new: true},}},{id: 4,category_id: 41,options: {'modelName31': {size: '8 feet',colour: 'red',is_new: true},'modelName32': {size: '8 feet',colour: 'red',is_new: true},}}]

let x = products_row.flatMap(({options,...rest}) => Object.entries(options).map(([k,v]) => ({...v,...rest,model:k})))

console.log(x)

CodePudding user response:

It is quite hard to analyze your solution and reason about your idea, so I cannot fix your code.

What you want to do is to extract options from each object and attach the rest of object, in other words you want to iterate over each option for each product row.

There are numerous ways to achieve this, you can use flatMap as @cmgchess suggested. Easier to understand is something like this:

let result = [];

products_row.forEach(({ options, ...rest }) =>
  Object.values(options).forEach((b) => result.push({ ...rest, ...b })),
);
  • Related