I have currently the challenge to convert the following data:
{ "fieldname1": "value", "fieldname3": [ "value 1", [ [ "firstname", "lastname" ] ] ], "fieldname2": [ [ [ "value 3" ], "full name" ] ] }
into the following:
{ "fieldname1": "value", "fieldname3": { "field3_sub1": "value 1", "field3_sub2": [ { "field3_sub2_1": "firstname", "field3_sub2_2": "lastname" } ] }, "fieldname2": [ { "field2_sub1": [ "value 3" ], "field2_sub2": "full name" } ] }
I’m currently a bit lost how I could convert the source data into the expected object.
I get the data from a sql query ( presto ).
The structured information ( fieldname2
and fieldname3
) aren’t resolved, I get only the values in the response.
The field position at root level is dynamic ( could be fieldname1
, fieldname2
, fieldname3
but also fieldname3
, fieldname1
, fieldname2
).
The value position inside fieldname2
and fieldname3
seems to be static.
I already solved the challenge to convert the given table schema into a JSONSchema:
{ "type": "object", "properties": { "fieldname2": { "type": "array", "items": { "type": "object", "properties": { "field2_sub1": { "type": "array", "items": { "type": "string" } }, "field2_sub2": { "type": "string" } }, "additionalProperties": false, "title": "fieldname2" } }, "fieldname1": { "type": "string" }, "fieldname3": { "type": "object", "properties": { "field3_sub1": { "type": "string" }, "field3_sub2": { "type": "array", "items": { "type": "object", "properties": { "field3_sub2_1": { "type": "string" }, "field3_sub2_2": { "type": "string" }, }, "additionalProperties": false, "title": "field3_sub2" } } }, "additionalProperties": false, "title": "fieldname3" } }, "additionalProperties": false }
Based on the JSONSchema I was able to generate a “model definition” which will be used in a code generator:
{ "Fieldname2": { "root": false, "fields": { "field2_sub1": { "name": "field2_sub1", "fieldType": "string[]", "graphqlType": "[String]", "nullable": true, "filter": false }, "field2_sub2": { "name": "field2_sub2", "fieldType": "string", "graphqlType": "String", "nullable": true, "filter": true } } }, "Field3_sub2": { "root": false, "fields": { "field3_sub2_1": { "name": "field3_sub2_1", "fieldType": "string", "graphqlType": "String", "nullable": true, "filter": true }, "field3_sub2_2": { "name": "field3_sub2_2", "fieldType": "string", "graphqlType": "String", "nullable": true, "filter": true } } }, "Fieldname3": { "root": false, "fields": { "field3_sub1": { "name": "field3_sub1", "fieldType": "string", "graphqlType": "String", "nullable": true, "filter": true }, "field3_sub2": { "name": "field3_sub2", "fieldType": "Field3_sub2[]", "graphqlType": "[Field3_sub2]", "nullable": true, "filter": false } } }, "Record": { "root": true, "fields": { "fieldname2": { "name": "fieldname2", "fieldType": "Fieldname2[]", "graphqlType": "[Fieldname2]", "nullable": true, "filter": false }, "fieldname1": { "name": "fieldname1", "fieldType": "string", "graphqlType": "String", "nullable": true, "filter": true }, "fieldname3": { "name": "fieldname3", "fieldType": "Fieldname3", "graphqlType": "Fieldname3", "nullable": true, "filter": false } } } }
Advertisement
Answer
Based on the comment from @nikhil, I spent an hour to create a running prototype.
I have tested it successfully with the provided example data and real data.
It worked in both cases.
const transformObject = (data, definition) => { let res = {}; // get the field names from the definition const definitionFields = Object.keys(definition); for (let iElement = 0; iElement < data.length; iElement++) { // get the current property name const propName = definitionFields[ iElement ] // get the definition for the current field const fieldDefinition = definition[ propName ]; // in case the current value is a simple type, return it if (fieldDefinition.type !== "array" && fieldDefinition.type !== "object") { res[ propName ] = data[ iElement ]; } // if the expected value for the current property is an object, // run the object transformation if (fieldDefinition.type === "object") { res[ propName ] = transformObject( data[ iElement ], fieldDefinition.properties ); } // if the expected value for the current property is an array, // run the array transformation if (fieldDefinition.type === "array") { res[ propName ] = transformArray( data[ iElement ], fieldDefinition.items ); } } return res; }; const transformArray = (data, definition) => { // in case we have a simple type like string, number, etc. // use the given data as return value if (definition.type !== "object") { return data; } // otherwise run the transform object function // to generate the key/value pair // NOTE: Since I don't have array of arrays in my usecase // I didn't implemented the check for arrays // i assume that the return value should be always // an array of object or array of string/number/boolean return data.map((ele) => { return transformObject(ele, definition.properties); }); }; const transform = (data, definition) => { let res = {}; for (const [ key, value ] of Object.entries(data)) { // get the current field definition from the schema const fieldDefinition = definition[ key ]; // for simple types like string, number, etc. we don't have // to run a transformation, just return the given value if (fieldDefinition.type !== "object" && fieldDefinition.type !== "array") { res[ key ] = value; } // in case of an object, run the object transformation if (fieldDefinition.type === "object") { res[ key ] = transformObject(value, fieldDefinition.properties); } // in case of an array, run the array transformation if (fieldDefinition.type === "array") { res[ key ] = transformArray(value, fieldDefinition.items); } } return res; }; const source = { /** * The provided data from the question */ } const schema = { /** * the provided JSONSchema from the question */ } const transformed = transform(source, schema.properties); console.log(JSON.stringify(transformed, null, 2))