Search code examples
javascriptrecursionecmascript-6lodashjavascript-objects

Recursively fitting JavaScript object to a specific structure


I have this problem where I cant really figure out how to implement this in code. I think that I will have to use to power of recursion to do this, but I am really struggling with it.

I have this object (simplified for this question), where the nested depths can be unknown.

 const allValues = {
  features: {
    title: 'features',
    description: 'some features',
    fields: {
      featureA: false,
      featureB: true,
      featureC: true
    }
  },
  otherthings: {
    title: 'otherthings',
    description: 'otherthingsdescription',
    fields: {
      nestedotherthings: {
        title: 'nestedotherthings',
        description: 'nestedotherthingsdescription',
        fields: {
          againnested: {
            title: 'againsnested',
            description: 'againsnested',
            fields: {
              finallynestedvalue: 1
            }
          },
          againnested2: {
            title: 'againsnested2',
            description: 'againsnested2',
            fields: {
              finallynestedvalue: 200
            }
          }
        }
      }
    }
  }
}

I want to run this object through some code and get an output like this:

  const expected_output = {
  features: {
    featureA: false,
    featureB: true,
    featureC: true
  },
  othertings: {
    nestedotherthings: {
      againnested: {
        finallynestedvalue: 1
      },
      againnested2: {
        finallynestedvalue: 2
      }
    }
  }
}

What I have tried:

 const output = _(allValues).mapValues((value, key) => flattenFields({}, value, key)).value()

function flattenFields(parent, current, key) {
  if (!current || !current.fields) {
    return current
  }

  return {
    ...parent,
    [key]: _(current.fields).mapValues((value, key) => flattenFields(current, value, key)).value()
  }
}

I hope someone can help me with this and explain what I am doing wrong.


Solution

  • You could take a recursive approach by checking the values and if an object take the fields property or the value. Then rebuild a new object.

    function convert(object) {
        return Object.fromEntries(Object
            .entries(object)
            .map(([k, v]) => [k, v && typeof v === 'object' ? convert(v.fields) : v])
        );
    }
    
    var data = { features: { title: 'features', description: 'some features', fields: { featureA: false, featureB: true, featureC: true } }, otherthings: { title: 'otherthings', description: 'otherthingsdescription', fields: { nestedotherthings: { title: 'nestedotherthings', description: 'nestedotherthingsdescription', fields: { againnested: { title: 'againsnested', description: 'againsnested', fields: { finallynestedvalue: 1 } }, againnested2: { title: 'againsnested2', description: 'againsnested2', fields: { finallynestedvalue: 200 } } } } } } },
        result = convert(data);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }