简体   繁体   中英

JS push object with dynamic keys and values to an array

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.

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)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM