简体   繁体   中英

Modify structure of deeply nested object into an array of objects

I have a deeply nested javascript object, which can contain a properties field- which is an object where the key represent the property name and the values represent the rest of the property data. I want to transform the property object into an array of objects where the key is combined with the values. For example, this is what i have:

const test = {
    properties: {
      meta: {
        type: 'object',
        properties: {
          agencyId: {
            type: 'string',
            example: 'e767c439-08bf-48fa-a03c-ac4a09eeee8f',
            description: 'agencyId',
          },
        },
      },
      data: {
        type: 'object',
        properties: {
          intervalStartTime: {
            type: 'string',
            description: 'Time in GMT',
            example: '1591702200000',
          },
          group: {
            type: 'object',
            properties: {
              groupType: {
                type: 'string',
                description: 'Group Type',
                example: 'vip',
              },
              numberofRequests: {
                type: 'number',
                example: 10198,
                description: 'Amount of requests coming from group',
              },
            },
          },
        },
      },
    },
  }

And this is what i want:

const test = {
  properties: [
    {
      name: 'meta',
      type: 'object',
      properties: [
        [
          {
            type: 'string',
            example: 'e767c439-08bf-48fa-a03c-ac4a09eeee8f',
            description: 'agencyId',
            name: 'agencyId',
          },
        ],
      ],
    },
    {
      name: 'data',
      type: 'object',
      properties: [
        [
          {
            type: 'string',
            description: 'Time in GMT',
            example: '1591702200000',
            name: 'intervalStartTime',
          },
          {
            name: 'group',
            type: 'object',
            properties: [
              {
                name: 'groupType',
                type: 'string',
                description: 'Group Type',
                example: 'vip',
              },
              {
                name: 'numberOfRequests',
                type: 'number',
                example: 10198,
                description: 'Amount of requests coming from group',
              },
            ],
          },
        ],
      ],
    },
  ],
}

I have a helper function that converts the objects into the form that I want, but I am struggling with recursively modifying the nested properties. This is what I have. Any suggestions on how I can modify the entire object into the structure that I need?

 const convertObj = (obj) => {
    return Object.entries(obj).reduce((initialVal, [name, nestedProperty]) => {
      initialVal.push({ ...nestedProperty, name })
      return initialVal
    }, [])
  }

 const getNestedProperties = (data) => {
    for (const key in data) {
      const keyDetails = data[key]
      if (keyDetails.hasOwnProperty('properties')) {
        const keyProperties = keyDetails['properties']
        keyDetails['properties'] = []
        keyDetails['properties'].push(convertObj(keyProperties))
        getNestedProperties(keyProperties)
      }
    }
  }

If the object has a properties key, map the entries and create an array of objects with each key as name and rest of the value. Loop through the object and check if each property is an object. If yes, recursively call the function. The {...o } part creates a copy of the input, so that it isn't mutated.

 const test = {properties:{meta:{type:"object",properties:{agencyId:{type:"string",example:"e767c439-08bf-48fa-a03c-ac4a09eeee8f",description:"agencyId",},},},data:{type:"object",properties:{intervalStartTime:{type:"string",description:"Time in GMT",example:"1591702200000",},group:{type:"object",properties:{groupType:{type:"string",description:"Group Type",example:"vip",},numberofRequests:{type:"number",example:10198,description:"Amount of requests coming from group",}}}}}}}; function convert({...o }) { for (const key in o) { if (typeof o[key] === 'object') o[key] = convert(o[key]) } if (o.hasOwnProperty("properties")) o.properties = Object.entries(o.properties).map(([name, v]) => ({ name, ...v })) return o } console.log(convert(test))

If you have no properties property, just return the rest of the object. If you do, return the rest of the object plus a properties array property formed by taking each name-value entry in that property and converting it into an object by adding the property name to the result of calling transform on that value .

The code is fairly simple:

 const transform = ({properties, ...rest} = {}) => properties? {... rest, properties: Object.entries (properties).map (([name, val]) => ({ name, ... transform (val) })) }: {... rest} const test = {properties: {meta: {type: 'object', properties: {agencyId: {type: 'string', example: 'e767c439-08bf-48fa-a03c-ac4a09eeee8f', description: 'agencyId'}}}, data: {type: 'object', properties: {intervalStartTime: {type: 'string', description: 'Time in GMT', example: '1591702200000'}, oup: {type: 'object', properties: {grupType: {type: 'string', description: 'Group Type', example: 'vip'}, numberofRequests: { type: 'number', example: 10198, description: 'Amount of requests coming from group'}}}}}}} console.log (transform (test))
 .as-console-wrapper {max-height: 100%;important: top: 0}

Here is a solution where object-scan does the heavy lifting. Note that this works because traversal happens in delete safe order.

 // const objectScan = require('object-scan'); const test = { properties: { meta: { type: 'object', properties: { agencyId: { type: 'string', example: 'e767c439-08bf-48fa-a03c-ac4a09eeee8f', description: 'agencyId' } } }, data: { type: 'object', properties: { intervalStartTime: { type: 'string', description: 'Time in GMT', example: '1591702200000' }, group: { type: 'object', properties: { groupType: { type: 'string', description: 'Group Type', example: 'vip' }, numberofRequests: { type: 'number', example: 10198, description: 'Amount of requests coming from group' } } } } } } }; const rewrite = (obj) => objectScan(['**.properties'], { rtn: 'count', // returns number of rewrites filterFn: ({ value, parent, property }) => { parent[property] = Object.entries(value).map(([name, v]) => ({ name, ...v })); } })(obj); console.log(rewrite(test)); // => 4 console.log(test); // => { properties: [ { name: 'meta', type: 'object', properties: [ { name: 'agencyId', type: 'string', example: 'e767c439-08bf-48fa-a03c-ac4a09eeee8f', description: 'agencyId' } ] }, { name: 'data', type: 'object', properties: [ { name: 'intervalStartTime', type: 'string', description: 'Time in GMT', example: '1591702200000' }, { name: 'group', type: 'object', properties: [ { name: 'groupType', type: 'string', description: 'Group Type', example: 'vip' }, { name: 'numberofRequests', type: 'number', example: 10198, description: 'Amount of requests coming from group' } ] } ] } ] }
 .as-console-wrapper {max-height: 100%;important: top: 0}
 <script src="https://bundle.run/object-scan@13.7.1"></script>

Disclaimer : I'm the author of object-scan

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