0

I have an array of objects each object has one nested object I need to modify that

Example: What I have below

const array = [{
    asset: {key: '1235', type: 'mocFirst'},
    id: 27,
    marketValuey: 6509,
    marketValueySecond: 65033,
    marketValueyThird: 650900,
}]

I want get that:

const array = [{
    type: 'mocFirst'
    key: '1235',
    id: 27,
    marketValuey: 6509,
    marketValueySecond: 65033,
    marketValueyThird: 650900,
}]

There is my solution

const array = [{
    asset: {key: '1235', type: 'mocFirst'},
    id: 27,
    marketValuey: 6509,
    marketValueySecond: 65033,
    marketValueyThird: 650900,
},
    {
        asset: {key: '12', type: 'mocFirst44'},
        id: 27,
        marketValuey: 6409,
        marketValueySecond: 64033,
        marketValueyThird: 640900,
    },
    {
        asset: {key: '1299', type: 'mocFirst'},
        id: 271,
        marketValuey: 6109,
        marketValueySecond: 61033,
        marketValueyThird: 610900,
    },
    {
        asset: {key: '1296', type: 'mocFirst'},
        id: 272,
        marketValuey: 65092,
        marketValueySecond: 650332,
        marketValueyThird: 6509020,
    },

]

    const resultArr = array.map(item => {
    const { asset, ...newObj} = item;
    const { key, type } = item.asset;
    return { key, type, ...newObj};

});

Any things about my solution? Maybe it can be done better? In production, I will have a big array

pridan
  • 163
  • 1
  • 6
  • 1
    Looks fine. Did you run into any trouble? – James Mar 29 '22 at 15:18
  • 2
    This isn't really the right site for reviewing working code, unless you have a specific problem to solve/goal to achieve (In which case, please include it in the question) – DBS Mar 29 '22 at 15:19
  • 2
    I don't recommend what was suggested about using `{ key:key }`. The language has more concise syntax for that and it's just `{ key }` so keep using it as you are. – Wyck Mar 29 '22 at 15:23
  • I have trouble with performance. Below, I got an answer, thanks – pridan Mar 29 '22 at 18:21

6 Answers6

4

Here you go, it's a recursive solution to flatten the object

function flat(source, target) {
  Object.keys(source).forEach(function(k) {
    if (source[k] !== null && typeof source[k] === 'object') {
      flat(source[k], target);
      return;
    }
    target[k] = source[k];
  });
}

const array = [{
    asset: {
      key: '1235',
      type: 'mocFirst'
    },
    id: 27,
    marketValuey: 6509,
    marketValueySecond: 65033,
    marketValueyThird: 650900,
  },
  {
    asset: {
      key: '12',
      type: 'mocFirst44'
    },
    id: 27,
    marketValuey: 6409,
    marketValueySecond: 64033,
    marketValueyThird: 640900,
  },
  {
    asset: {
      key: '1299',
      type: 'mocFirst'
    },
    id: 271,
    marketValuey: 6109,
    marketValueySecond: 61033,
    marketValueyThird: 610900,
  },
  {
    asset: {
      key: '1296',
      type: 'mocFirst'
    },
    id: 272,
    marketValuey: 65092,
    marketValueySecond: 650332,
    marketValueyThird: 6509020,
  },

]
let flatArr = array.map(item => {
  let flatObj = {};
  flat(item, flatObj);
  return flatObj
});
console.log(flatArr);
Vivek Sharma
  • 531
  • 6
  • 20
1

Just flatten it out like so:

var outArr = array.map(item => {
   // Create the new items
   item.key = item.asset.key
   item.type = item.asset.item
   // Delete the old parent
   delete item.asset
   return item
})
1

The only speed-up that you can 'potentially' introduce is via the use of a for loop instead of a map method. This does unfortunately depend on how the compiler will optimize your code and the effects will only become noticeable if you are working with very large arrays. Benchmarking can be referenced here.

The final part of your code should look like this:

const resultArr = [];
for (let i = 0; i < array.length; i += 1) {
  const { asset, ...newObj} = array[i];
  const { key, type } = asset;
  resultArr.push({ key, type, ...newObj});
}

It is important to understand that the speedup of this code will not be very noticeable and developers usually prefer more obvious/maintainable syntax, so your original answer can be considered correct. Hence, use this at your own discretion.

Ovidijus Parsiunas
  • 2,512
  • 2
  • 8
  • 18
1

If you just need to transform asset.key and asset.type respectively into key and type, and you want to increase performance, manual assignment of fields is around 4-5 times faster than your solution.
e.g. I have created an array with 1000 items to compare your solution (which takes around 2.5 ms to create array1) with mine (around 0.5 ms to create array2).

const N = 1000;
let array = [];
for (let i = 0; i < N; i++) {
  let random_item = {
    asset: {
      key: Math.random(N),
      type: 'mocFirst'
    },
    id: Math.random(N),
    marketValuey: Math.random(N),
    marketValueySecond: Math.random(N),
    marketValueyThird: Math.random(N)
  };
  array.push(random_item);
}

const t0 = performance.now();
const array1 = array.map(item => {
  const {
    asset,
    ...newObj
  } = item;
  const {
    key,
    type
  } = item.asset;
  return {
    key,
    type,
    ...newObj
  };
});
console.log(array1[10]);
const t1 = performance.now();
console.log(`Operation took ${t1 - t0} milliseconds.`);

let array2 = [];
for (let i = 0; i < array.length; i++) {
  array2.push({
    key: array[i].asset.key,
    type: array[i].asset.type,
    id: array[i].id,
    marketValuey: array[i].marketValuey,
    marketValueySecond: array[i].marketValueySecond,
    marketValueyThird: array[i].marketValueyThird,
  });
}
console.log(array2[10]);
const t2 = performance.now();
console.log(`Operation took ${t2 - t1} milliseconds.`);
Alessio Cantarella
  • 5,077
  • 3
  • 27
  • 34
1

I like this solution, which I found by searching for "flatten nested object in javascript".

Here is the code in action from my favorite answer:

const crushObj = (obj = {}) => Object.keys(obj || {}).reduce((acc, cur) => {
  if (typeof obj[cur] === 'object') {
    acc = { ...acc, ...crushObj(obj[cur])}
  } else { acc[cur] = obj[cur] }
  return acc
}, {})

const obj = {
  a:2,
  b: {
    c:3
  }
}

const output = crushObj(obj)
console.log(output)
// { a: 2, c: 3 }

It would be great for a library like Lodash to offer support for this.

Jake Cronin
  • 1,002
  • 13
  • 15
1

I would use a concept of destructuring.

array.map((elem) => {
 const {
    id, 
    marketValuey, 
    marketValueySecond, 
    marketValueyThird, 
    asset: {key}, 
    asset: {type}
 } = elem;
 
 return {
  id,
  marketValuey, 
  marketValueySecond, 
  marketValueyThird, 
  key, 
  type
  }
})

for more detailed concept of destructuring refer - nested-destructuring

Sourav Suman
  • 23
  • 11