how to navigate through complex JSON dynamically in JavaScript - javascript

I'm trying to navigate through a complex nested JSON, however my attempt didn't get me too far as it keeps returning me the last index JSON.
This is how my Objects looks like, and trying to navigate through it and getting other objs/schemas that are in $ref.
Raw JSON
{
"type": "object",
"properties": {
"Id": {
"format": "int32",
"type": "integer"
},
"Status": {
"enum": [
"Preparing",
"AwaitingCompletion",
"Cancelled",
"Completed"
],
"type": "string"
},
"ExternalReference": {
"type": "string"
},
"Customer": {
"$ref": "#/definitions/Customer"
},
"OrderLineGroups": {
"type": "array",
"items": {
"$ref": "#/definitions/OrderLineGroup"
}
},
"Promotions": {
"type": "array",
"items": {
"$ref": "#/definitions/PromotionSummary"
}
},
"OriginatingSite": {
"type": "object",
"properties": {
"Id": {
"format": "int32",
"type": "integer"
},
"PropertyCode": {
"type": "string"
},
"StoreCode": {
"type": "string"
}
}
},
"CustomData": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "object"
}
}
}
}
}
In my code I have done for() and hasOwnProperty(), however my problem is that it doesn't give me all the JSON back even the condition is met (e.g if there's no type property), it only gives the last index or object that doesn't have type property. Also doesn't return me any of the objects if type property is array.
// Get property of #/definitions/obj
let prop = apiDefinition[splitResponse.split('/')[2]].properties;
console.log([prop])
var s = [apiDefinition[splitResponse.split('/')[2]].properties];
// Transform JS Object of #/definitions/Obj to JSON
var parentJSON = JSON.stringify(apiDefinition[splitResponse.split('/')[2]]);
for (var x in prop) {
if (prop.hasOwnProperty(x)) {
if (prop[x].type && prop[x].type === 'array') {
console.log('All type Array >> ', x);
let objKeyProp = apiDefinition[prop[x].items.$ref.split('/')[2]];
let objJsonStringified = JSON.stringify(objKeyProp);
let refString = '{"$ref"'+':' + '"' + prop[x].items.$ref + '"}';
this.compiledJson = JSON.parse(parentJSON.replace(refString, objJsonStringified));
} else if (!prop[x].type) {
console.log('all arrays >> ', x)
let objKeyProp = apiDefinition[prop[x].$ref.split('/')[2]];
let objJsonStringified = JSON.stringify(objKeyProp);
let refString = '{"$ref"'+':' + '"' + prop[x].$ref + '"}';
this.compiledJson = JSON.parse(parentJSON.replace(refString, objJsonStringified));
}
}
}

Related

How could one define the exact data types at any level of a nested object / array data-structure?

I am trying to define a "complex" object:
var tM = JSON.parse('{"version":"","series":[{"name":"","possModes":[],"instance":[{"date":"","mode":""}]}]}');
where all items of array "instance" should be objects of type
{"date":"","mode":""}
and all items of array "series" should be objects of type
{"name":"","possModes":[],"instance":[{"date":"","mode":""}]}
The problem is that only the items of index [0] are getting the proper properties and items of higher indexes are "undefined", so I cannot set them to their needed values.
I have also tried to define tM explicitly, like:
var Cinstance = new Object();
Cinstance.date = "";
Cinstance.mode = "";
var Cseries = new Object();
Cseries.name = '';
Cseries.possModes = [];
Cseries.instance = [new Object(Cinstance)];
var tM= new Object();
tM.version = "";
tM.series = [new Object(Cseries)];
and also like:
var tM = {series:
[{instance:
[{date:"",mode:""}
]
}
]
}
(this is a version reduced to my specific problem).
Of course, they both end up with the same result - only items of index [0] are defined.
The data structure provided by the OP ...
{
"version": "",
"series": [{
"name": "",
"possModes": [],
"instance": [{
"date": "",
"mode": ""
}]
}]
}
... does validate against the following JSON schema ...
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "My-Special-Schema-Or-Data-Structure-Title",
"description": "Whatever I have to say about my described structure",
"type": "object",
"properties": {
"version": {
"description": " ... ",
"type": "string"
},
"series": {
"description": " ... ",
"type": "array",
"minItems": 1,
"items": {
"description": " ... ",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"possModes": {
"description": " ... ",
"type": "array"
},
"instance": {
"description": " ... ",
"type": "array",
"minItems": 1,
"items": {
"description": " ... ",
"type": "object",
"properties": {
"date": {
"type": "string"
},
"mode": {
"type": "string"
}
},
"required": [
"date",
"mode"
]
}
}
},
"required": [
"name",
"possModes",
"instance"
]
}
}
},
"required": [
"version",
"series"
]
}
There is even a JSON Schema Generator one could start with. Passing the OP's originally provided data structure, one gets a solid base of a JSON Schema, one then can continue tailoring.

Error in generating a valid json recursive javascript function

I have a function to generate an object which I'm transforming to a JSON later on:
function createSearchCriteria(payload) {
var output = [];
if (payload['searchCriteria'] != null) {
for (var i = 0; i < payload['searchCriteria'].length; i++) {
var content = payload['searchCriteria'][i];
output[i] = {};
if (content['grouping'] != null) {
output[i]['groupOperator'] = content['grouping'];
output[i]['searchCriteria'] = [];
output[i]['searchCriteria'].push(createSearchCriteria(content))
} else {
output[i]['name'] = content['name'];
output[i]['type'] = content['type'];
}
}
}
return output
}
The input payload for this method is also a JSON value parsed
payload = JSON.parse(request);
The input structure is almost the same as the output, the only difference is the "grouping" attribute, which in the output is called "groupOperator".
I have implemented my function recursive because we can have different levels of search criteria.
Even though the searchCriteria in the input has only one [] each.
Why does each searchCriteria in the result comes with 2 pairs of squared brackets?
{
"searchCriteria": [
{
"groupOperator": "AND",
"searchCriteria": [
[
{
"groupOperator": "OR",
"searchCriteria": [
[
{
"name": "FirstName",
"type": "string"
},
{
"name": "LastName",
"type": "string"
},
{
"name": "MiddleName",
"type": "string"
},
{
"name": "Document",
"type": "string"
},
{
"name": "DOB",
"type": "date"
},
{
"name": "CdrId",
"type": "string"
}
]
]
},
{
"groupOperator": "AND",
"searchCriteria": [
[
{
"name": "Active",
"type": "bool"
},
{
"name": "Id",
"type": "int"
},
{
"name": "CountryId",
"type": "int"
}
]
]
}
]
]
}
],
"groupOperator": "AND"
}
Thanks in advance for your help.
try
output[i]['searchCriteria'] = createSearchCriteria(content)
instead of
output[i]['searchCriteria'] = [];
output[i]['searchCriteria'].push(createSearchCriteria(content))

why arrow function return undefined

I'm writing a function that simply loops through a Json schema. Let us say we have a simple json schema such as:
var foo = {
"description": "A car schema",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_rev": {
"type": "string"
},
"sources": {
"type": "object",
"properties": {
"mam": {
"type": "object",
"properties": {
"source_id": {
"type": [ "integer", "null" ]
},
"SOR": {
"type": ["boolean","null"]
}
}
},
"sas": {
"type": "object",
"properties": {
"source_id": {
"type": "string"
},
"SOR": {
"type": ["boolean","null"]
},
"CAR": {
"type": ["object","null"]
}
}
}
}
}
}
}
We're trying to collect the type of the key object from it. Here is function search for CAR type should return => "object"
parseObjectProperties = (obj)=> {
for (var k in obj) {
if(k === "CAR"){
console.log(_.values(obj[k])[0][0]) // When I do a console log like this prin the object value
return _.values(obj[k])[0][0] // but in return i get undefined
}
if ( _.isObject( obj[k]) && !_.isNil(obj[k])) {
return parseObjectProperties(obj[k])
}
}
}
parseObjectProperties(foo);
When I run it, the inner console.log(_.values(obj[k])[0][0]) shows the correct value: object
but if i run it
console.log(parseObjectProperties(foo));
I get
undefined
Why isn't the function properly returning the correct value => "object"?
Thank you!
I just re-wrote this as I didn't understand the logic you were using. Does this solve your problem?
FYI your object CAR, has a property named type whose value is an array that contains 2 values, "object" and "null" so you want to use obj[k].type[0] if you want to get "object" as the result.
const parseObjectProperties = (obj) => {
var result = null;
for (var k in obj)
if (k == "CAR") return obj[k].type[0];
else if (obj[k] instanceof Object)
result = parseObjectProperties(obj[k]);
return result;
}
var foo = {
"description": "A car schema",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_rev": {
"type": "string"
},
"sources": {
"type": "object",
"properties": {
"mam": {
"type": "object",
"properties": {
"source_id": {
"type": ["integer", "null"]
},
"SOR": {
"type": ["boolean", "null"]
}
}
},
"sas": {
"type": "object",
"properties": {
"source_id": {
"type": "string"
},
"SOR": {
"type": ["boolean", "null"]
},
"CAR": {
"type": ["object", "null"]
}
}
}
}
}
}
}
console.log(parseObjectProperties(foo));

How to describe and validate an array of objects with cuid as key and value as an object with specific properties

I have a unique data that I am attempting to validate:
{
"name": "Some random name",
"blocks": [
{"cj5458hyl0001zss42td3waww": {
"quantity": 9,
"rate": 356.77,
"dId": "ewdwe4434"
}},
{"cj5458hyl0001zss42td3wawu": {
"quantity": 4,
"rate": 356.77,
"dId": "3434ewdwe4434"
}}]
}
Here is the composition that I have right now (invalid and incorrect):
const subSchema = {
"type": ["string"],
"pattern": "/^c[^\s-]{8,}$/",
"properties": {
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"dId": {
"type": "string"
}
},
"required": ["quantity", "rate", "dId"]
};
const schema = {
"type": ["object"],
"properties": {
"name": {
"type": "string"
},
"blocks": {
"type": "array",
"items": subSchema,
"uniqueItems": true,
"minItems": 1
}
},
"required": ["name", "blocks"]
};
and how I am validating it (for context):
const { BadRequestError } = require("restify");
const ajv = require("ajv");
var schemaValidator = ajv();
const validateRoomTypePostRequest = (req, res, next) => {
if (req.body && req.body.data){
const blockReq = Object.assign({}, req.body.data);
const testSchemaValidator = schemaValidator.compile(schema);
const valid = testSchemaValidator(blockReq);
if (!valid) {
const messages = testSchemaValidator.errors.map(e => {
return e.message;
});
return next(new BadRequestError(JSON.stringify(messages)));
}
return next();
}
else {
return next(new BadRequestError("Invalid or non-existent request body"));
}
};
Here is what I have referenced so far:
1) AJV schema validation for array of objects
2) https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md
3) https://spacetelescope.github.io/understanding-json-schema/reference/object.html
Additional information:
1) Using Node 8.1.3
2) AJV version 5.2
I know that I need to use an array of items to describe the object. However the object contains a unique cuid as a key and the value as a an object. I would like to understand how to describe this data using such a schema that validates the nested properties and the cuid. I welcome feedback on how to best approach this data. Thank you for your time.
I did some soul searching and realized that all I had to do was leverage the patternPropertieskeyword, specific to strings.
{
"blockType": {
"additionalProperties": false,
"type": "object",
"properties": {
"name": {
"type": "string"
},
"blocks": {
"type": "array",
"items": {
"type": "object",
"patternProperties": {
"^[a-z][a-z0-9\\-]*$": {
"type": ["object"],
"properties": {
"rate": {
"type": ["integer"]
},
"quantity": {
"type": ["integer"]
},
"dId": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["dId", "quantity", "rate"]
}
}
}
}
},
"required": ["name", "blocks"]
}
}
I could improve the regex for validating the cuid.

Converting a json schema to angular-tree-control treemodel

I have a very large json schema which I would like to display in an Angular Tree Control. However, the json schema is not exactly in the treemodel format supported by the Angular Tree Control. For example, the children (properties) in the schema are not in an array. How would I go about converting the json schema into a treemodel format?
The schema looks something like this (except more complicated with up to 10 levels of nesting):
{
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"address": {
"type": "object",
"properties": {
"addressLine1": {
"type": "string"
},
"addressLine2": {
"type": "string"
}
}
}
}
}
For it to render correctly in the Angular Tree Control, it needs to look like this:
{
"type": "object",
"properties": [
{
"name": "firstName",
"type": "string"
},
{
"name": "lastName",
"type": "string"
},
{
"name": "address",
"type": "object",
"properties": [
{
"name": "addressLine1",
"type": "string"
},
{
"name": "addressLine2",
"type": "string"
}
]
}
]
}
This is an example, can be refactored to be recursive to deeper levels.
var data = {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"address": {
"type": "object",
"properties": {
"addressLine1": {
"type": "string"
},
"addressLine2": {
"type": "string"
}
}
}
}
};
function toTreeModel(obj){
var treeModel = {};
for (var a in obj) {
if(a === 'properties'){
treeModel[a] = []
var i = 0;
var e = 0;
for(b in obj[a]){
if(obj[a][b].type === 'object'){
treeModel[a][i] = {name: b, type: obj[a][b].type, properties: []};
for(c in obj[a][b].properties){
treeModel[a][i].properties.push({name: c, type: obj[a][b].properties[c].type});
e++;
}
} else {
treeModel[a][i] = {name: b, type: obj[a][b].type};
}
i++;
}
} else {
treeModel[a] = obj[a];
}
}
return treeModel;
}
var toTree = toTreeModel(data);
// console.log(toTree);
document.getElementById("output").innerHTML = JSON.stringify(toTree, undefined, 2);
<pre id="output">
</pre>
it support nested also
var data = {
"type": "object",
"properties": {
"checked": {
"type": "boolean",
},
"dimensions": {
"type": "object",
"properties": {
"width": {
"type": "integer",
},
"height": {
"type": "integer",
},
"volume": {
"type": "object",
"properties": {
"length": {
"type":"integer",
},
"breadth":{
"type": "integer"
}
}
}
}
},
"id": {
"type": "integer",
},
"name": {
"type": "string",
},
"price": {
"type": "number",
}
}
}
function findProperties(obj){
let properties = []
for(key in obj){
if(obj[key].properties){
properties.push({name: key, datatype: obj[key].type, properties: findProperties(obj[key].properties)})
}else{
properties.push({ name: key, datatype: obj[key].type});
}
}
return properties;
}
function findData(data){
let result = "";
for(key in data){
if(key == 'properties'){
result = findProperties(data.properties)
}
}
return result;
}
console.log(JSON.stringify(findData(data)));

Categories