Reputation: 11
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)
}
}
}
Upvotes: 1
Views: 1121
Reputation: 2181
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/[email protected]"></script>
Disclaimer: I'm the author of object-scan
Upvotes: 0
Reputation: 50787
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}
Upvotes: 0
Reputation: 35222
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))
Upvotes: 1