Fell
Fell

Reputation: 135

Flatten Nested Objects and Output Array

I have a deeply nested object that has the following schema:

const data = {
  Car1: {
    key: "Car",
    value: "1",
    child: {
      Driver1: {
        key: "Driver",
        value: "1",
        child: {
          Trip1: {
            key: "Trip",
            value: 1,
            metrics: { distance: 1, time: 2 }
          }
        }
      },
      Driver2: {
        key: "Driver",
        value: "2",
        child: {
          Trip1: {
            key: "Trip",
            value: 1,
            metrics: { distance: 3, time: 4 }
          },
          Trip2: {
            key: "Trip",
            value: 2,
            metrics: { distance: 5, time: 6 }
          }
        }
      }
    }
  }
}

That I need to flatten into a singular array of objects, with each object in the array having all the properties of its direct child(ren).

Each nested object child is a Record of objects that have properties key and value.

The last object in the nested structure always has a property called metrics that should be flattened into the object as well.

So the output would look something like:

[
{ Car: 1, Driver: 1, Trip: 1, distance: 1, time: 2 },
{ Car: 1, Driver: 2, Trip: 1, distance: 3, time: 4 },
{ Car: 1, Driver: 2, Trip: 2, distance: 5, time: 6 }
]

I have tried the following code but it only captures one level of depth in the child tree:

  private flattenOutput(child: Record<string, OutputChild> = this.output): any[] {
    console.log('flattening', Object.keys(child));
    return Object.values(child).map((child) => {
      return Object.assign(
        {},
        { [child.key]: child.value },
        ...this.flattenOutput(child.child),
        child.metrics || {},
      );
    }, {});
  }

Upvotes: 0

Views: 266

Answers (2)

Mister Jojo
Mister Jojo

Reputation: 22265

I will do that this way :

data = 
  { Car1: { key: "Car", value: "1", child: 
      { Driver1: { key: "Driver", value: "1", child: 
          { Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2} } 
        } } 
      , Driver2: 
        { key: "Driver", value: "2", child: 
          { Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4} } 
          , Trip2: { key: "Trip", value: 2, metrics: { distance: 5, time: 6} } 
  } } } } } 

let result = []
for (let Car    in data )
for (let Driver in data[Car].child)
for (let Trip   in data[Car].child[Driver].child)
  result.push(
    { Car      : data[Car].value
    , Driver   : data[Car].child[Driver].value
    , Trip     : data[Car].child[Driver].child[Trip].value
    , distance : data[Car].child[Driver].child[Trip].metrics.distance
    , time     : data[Car].child[Driver].child[Trip].metrics.time
    })

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

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386540

By having correct nested objects, you could take a recursive approach and collect key/value and return a flat array with wanted objects.

const
    collect = (object, temp = {}) => Object
        .values(object)
        .flatMap(({ key, value, child, metrics }) => child
            ? collect(child, { ...temp, [key]: value })
            : { ...temp, [key]: value , ...metrics }
        ),
    data = { Car1: { key: "Car", value: "1", child: { Driver1: { key: "Driver", value: "1", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2 } } } }, Driver2: { key: "Driver", value: "2", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4 } }, Trip2: { key: "Trip",  value: 2, metrics: { distance: 5, time: 6 } } } } } } },
    result = collect(data);

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

Upvotes: 3

Related Questions