0

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 || {},
      );
    }, {});
  }
4
  • 1
    SO is not a free code writing service. What have you tried so far to solve this on your own? Commented Feb 10, 2021 at 18:23
  • @Andreas Added code Commented Feb 10, 2021 at 18:26
  • why Trip1 and Trip2 of Driver2 are not at the same level ? is it "logic" ? Commented Feb 10, 2021 at 18:37
  • @MisterJojo No, sorry! That's a typo, I wrote all the code out in SO so I messed up some of the indentation/nesting. Thanks for noticing - fixed Commented Feb 10, 2021 at 19:01

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

1 Comment

That's what I needed! I was missing the temp object in my function arguments. Thank you
0

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

2 Comments

Sure, but look at the solution from Nina. It's both more generic and more elegant. If there were more fields nested in a Trip, they would automatically be handled.
@ScottSauyet you guess wrong, I read Nina's answer before posting mine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.