Error in generating a valid json recursive javascript function - javascript

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))

Related

Compare Arrays and Remove Duplicates from the Final Array. Pokedex App

I create a Pokédex app, but i ran in some Problems with the double type Pokémon:
I call pokeapi twice to 2 endpoints (one for each Type), and i need to compare the Results in different Ways.
let a = {
"double_damage_from": [
{
"name": "ground",
"url": "https://pokeapi.co/api/v2/type/5/"
},
{
"name": "rock",
"url": "https://pokeapi.co/api/v2/type/6/"
},
{
"name": "water",
"url": "https://pokeapi.co/api/v2/type/11/"
}
],
"half_damage_from": [
{
"name": "bug",
"url": "https://pokeapi.co/api/v2/type/7/"
},
{
"name": "steel",
"url": "https://pokeapi.co/api/v2/type/9/"
},
{
"name": "fire",
"url": "https://pokeapi.co/api/v2/type/10/"
},
{
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
},
{
"name": "ice",
"url": "https://pokeapi.co/api/v2/type/15/"
},
{
"name": "fairy",
"url": "https://pokeapi.co/api/v2/type/18/"
}
],
"no_damage_from": []
};
let b = {
"double_damage_from": [
{
"name": "fighting",
"url": "https://pokeapi.co/api/v2/type/2/"
},
{
"name": "ground",
"url": "https://pokeapi.co/api/v2/type/5/"
},
{
"name": "steel",
"url": "https://pokeapi.co/api/v2/type/9/"
},
{
"name": "water",
"url": "https://pokeapi.co/api/v2/type/11/"
},
{
"name": "grass",
"url": "https://pokeapi.co/api/v2/type/12/"
}
],
"half_damage_from": [
{
"name": "normal",
"url": "https://pokeapi.co/api/v2/type/1/"
},
{
"name": "flying",
"url": "https://pokeapi.co/api/v2/type/3/"
},
{
"name": "poison",
"url": "https://pokeapi.co/api/v2/type/4/"
},
{
"name": "fire",
"url": "https://pokeapi.co/api/v2/type/10/"
}
],
"no_damage_from": []
};
I need to Compare the Data and get the Matches in a array.
This works fine and i got the 4x, 1x, and 1/4x damage in a array:
getMatch(a, b) {
let matches = [];
for (let i = 0; i < a.length; i++) {
for (let e = 0; e < b.length; e++) {
if (a[i].name === b[e].name) matches.push(a[i]);
}
}
return matches;
}
compareTypes(a, b) {
let four_damage_from = this.getMatch(a.double_damage_from, b.double_damage_from);
let double_damage_from = [];
let normal_damage_from = this.getMatch(a.double_damage_from, b.half_damage_from);
let half_damage_from = [];
let quarter_damage_from = this.getMatch(a.half_damage_from, b.half_damage_from);
let no_damage_from = this.getMatch(a.no_damage_from, b.no_damage_from);
let matches = { four_damage_from, double_damage_from, normal_damage_from, half_damage_from, quarter_damage_from, no_damage_from };
return matches;
}
to find the correct types for double_damage_from i have to merge a.double_damage_from and b.double_damage_from e.g. to c.double_damage_from. then i have to remove from c.double_damage_from all types that are in four_damage_from, normal_damage_from, quarter_damage_from, no_damage_from to get the correct 2x types, the same with half_damage_from.
I tried many solution but i didn't figure out how to solve this.
greetings Raphi
It Works with lodash, i need to think a bit about but basically works.
removeMatch(union, remove, double = false) {
union = _.differenceBy(union, remove.four_damage_from, 'name');
union = _.differenceBy(union, remove.normal_damage_from, 'name');
union = _.differenceBy(union, remove.quarter_damage_from, 'name');
// union = _.differenceBy(union, remove.no_damage_from, 'name');
if(double) {
union = _.differenceBy(union, remove.half_damage_from, 'name');
} else {
union = _.differenceBy(union, remove.double_damage_from, 'name');
}
return union;
}

how to navigate through complex JSON dynamically in 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));
}
}
}

Looping through an array of objects

I have the array of objects called res and am trying to loop through and organize the objects based on having one href, one method, and in some cases multiple schema, as with:
href: '/questions/{id}'
My issue is when I have multiple schema, if the current object I am in has '$schema' I want to check if the next object in the array also has '$schema'. If it does then I want to label the current schema object, requestSchema and the next object will be called responseSchema. But if the next object does not contain '$schema' then the current object will be labeled responseSchema.
I want to take res and turn it into
[{
"resource": "/questions",
"verb": "GET",
"schemaResponse": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"data": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"question": {
"type": "string",
"enum": [
"Favourite programming language?"
]
},
"published_at": {
"type": "string",
"enum": [
"2014-11-11T08:40:51.620Z"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1"
]
},
"choices": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"choice": {
"type": "string",
"enum": [
"Javascript"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1/choices/1"
]
},
"votes": {
"type": "number",
"enum": [
2048
]
}
},
"required": [
"choice",
"url",
"votes"
],
"additionalProperties": false
}]
}
},
"required": [
"question",
"published_at",
"url",
"choices"
],
"additionalProperties": false
}]
}
},
"required": [
"data"
]
}
}, {
"resource": "/questions/{id}",
"verb": "GET",
"schemaRequest": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
}
},
"required": [
"id"
]
},
"schemaResponse": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"question": {
"type": "string",
"enum": [
"Favourite programming language?"
]
},
"published_at": {
"type": "string",
"enum": [
"2014-11-11T08:40:51.620Z"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1"
]
},
"choices": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"choice": {
"type": "string",
"enum": [
"Javascript"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1/choices/1"
]
},
"votes": {
"type": "number",
"enum": [
2048
]
}
},
"required": [
"choice",
"url",
"votes"
],
"additionalProperties": false
}]
}
},
"required": [
"question",
"published_at",
"url",
"choices"
],
"additionalProperties": false
}
}
]
Everything works except for in the case of needing to have a request schema and a response schema.
const lodash = require('lodash');
var res = [
{ href: '/questions' },
{ method: 'GET' },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties: { data: [Object] },
required: [ 'data' ] },
{ href: '/questions/{id}',
hrefVariables: { element: 'hrefVariables', content: [Object] } },
{ method: 'GET',
headers: { element: 'httpHeaders', content: [Object] } },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties: { id: [Object] },
required: [ 'id' ] },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties:
{ question: [Object],
published_at: [Object],
url: [Object],
choices: [Object] },
required: [ 'question', 'published_at', 'url', 'choices' ] } ]
var arr = [];
var arrFinal = [];
var result = {};
for (var key = 0; key < res.length; key++) {
console.log(res[key]);
console.log(key);
var found = false;
for(var i = 0; i < arr.length; i++) {
//console.log((lodash.has(res[key], 'href')));
//console.log((lodash.has(res[key-1], '$schema')));
if ((lodash.has(arr[i], 'href'))) {
found = true;
break;
}
}
if ((lodash.has(res[key], '$schema')) && (lodash.has(res[key-1], '$schema'))) {
console.log('here');
result.schemaResponse = res[key];
result = lodash.omit(result, ['headers', 'properties', 'hrefVariables', 'required', 'href', 'method']);
break;
}
if((found === true) && (lodash.has(res[key], '$schema'))) {
var result = {};
console.log('there')
var combinedKeys = arr.reduce(function(a, item) {
Object.keys(item).map(function(key) {
if(key === 'href'){
result.resource = item[key];
}
if(key === 'method'){
result.verb = item[key];
} else {
result[key] = item[key];
}
});
return result;
}, {});
arr = [];
if((lodash.has(res[key+1], '$schema'))){
result.schemaRequest = res[key];
} else {
result.schemaResponse = res[key];
result = lodash.omit(result, ['headers', 'properties', 'hrefVariables', 'required', 'href', 'method']);
arrFinal.push(result);
result = {};
}
}
else {
console.log('hmmm');
var object = res[key];
arr.push(object);
}
}
var string = JSON.stringify(arrFinal, null, ' ')
console.log(arrFinal)
Based on this:
My issue is when I have multiple schema, if the current object I am in has '$schema' I want to check if the next object in the array also has '$schema'. If it does then I want to label the current schema object, requestSchema and the next object will be called responseSchema. But if the next object does not contain '$schema' then the current object will be labeled responseSchema.
and this (from my comment on your question):
Your question was a little unclear (I'd suggest proofreading it again and breaking up some of the run-on sentences). Are you saying that when you evaluate if ((lodash.has(res[key], '$schema')) && (lodash.has(res[key-1], '$schema'))) the value res[key-1] is always undefined?. So basically the 2nd if block never executes
Here is some pseudo-code to work into your code:
for ( var nIdx, crnt, next, key = 0, m = res.length; key < m; key++ ){
crnt = res[ key ]
next = res[ key + 1 ]
//do your checking here based on the existence of 'next'
if (next){ .... }
}
I'd test this on a simple loop and log the values of crnt and next to see if you're actually getting the expected results. If they are as expected, you can adjust your code to use those values instead of trying to access them dynamically with res[ key ] further down in your code.
I dunno, what the issue really is with your code, but this will be more readable at the least and will probably illuminate your error.

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)));

How to compare json elements and display data in multidimensional array if they match?

I have a JSON object at my disposal looking like this :
{
"Fields": [
{
"table": "catalogue",
"field": "Histo_Qtite",
"type": "STRING"
},
{
"table": "catalogue",
"field": "id_article",
"type": "STRING"
},
{
"table": "contact",
"field": "contact_email",
"type": "STRING"
},
{
"table": "contact",
"field": "contact_firestname",
"type": "STRING"
},
{
"table": "customer",
"field": "activity_type",
"type": "STRING"
},
{
"table": "customer",
"field": "adress",
"type": "STRING"
}
],
"Tables": [
{
"entity": "CATALOGUE",
"table": "catalogue"
},
{
"entity": "CLIENT",
"table": "customer"
},
{
"entity": "CONTACT",
"table": "contact"
}
]
}
I am trying to create a multidimensional array for every "Fields" objects base on the name of the table. To do so I experimented with javascript and it resulted in this code :
var objectPREFIX = "object_",
selectedObject = '',
objectArray = [],
objectImport = [],
OFImport = [],
TablesLength = jsonImport.Tables.length,
FieldsLength = jsonImport.Fields.length;
for (i = 0; i < FieldsLength; i++) {
selectedObject = objectPREFIX + jsonImport.Fields[i].table;
OFImport[selectedObject] = {
tableName : jsonImport.Fields[i].table,
FieldName : jsonImport.Fields[i].field,
fieldType : jsonImport.Fields[i].type
}
for (j = 0; j < TablesLength; j++) {
if(OFImport[selectedObject].tableName == jsonImport.Tables[j].table) {
objectImport.push(OFImport[selectedObject]);
objectArray[selectedObject] = OFImport[selectedObject];
}
}
}
console.log(objectArray);
The problem as I understand it is that OFImport[selectedObject] contain every object iteration of "Fields" and only display the last object in the console.
I would like to know how to make a comparison condition between "Fields" and "Tables" to get each iteration in separate arrays.
Here is a FIDDLE that demonstrates the issue (sorry if I have troubles articulating my explanation).
If I understand what your looking to do, which is have an array of tables, which has an array of fields, then I think you have your for loops backwards.
you need to loop your tables first, then add your fields like so:-
jsonImport = {
"Fields": [{
"table": "catalogue",
"field": "Histo_Qtite",
"type": "STRING"
}, {
"table": "catalogue",
"field": "id_article",
"type": "STRING"
}, {
"table": "contact",
"field": "contact_email",
"type": "STRING"
}, {
"table": "contact",
"field": "contact_firstname",
"type": "STRING"
}, {
"table": "customer",
"field": "activity_type",
"type": "STRING"
}, {
"table": "customer",
"field": "adress",
"type": "STRING"
}],
"Tables": [{
"entity": "CATALOGUE",
"table": "catalogue"
}, {
"entity": "CLIENT",
"table": "customer"
}, {
"entity": "CONTACT",
"table": "contact"
}]
}
var objectArray = [],
objectPREFIX = "object_",
selectedObject = '',
TablesLength = jsonImport.Tables.length,
FieldsLength = jsonImport.Fields.length;
for (i = 0; i < TablesLength; i++) {
selectedObject = objectPREFIX + jsonImport.Tables[i].table;
objectArray[selectedObject] = {
table: jsonImport.Tables[i].table,
entity: jsonImport.Tables[i].entity,
Fields: []
}
for (j = 0; j < FieldsLength; j++) {
if (jsonImport.Tables[i].table == jsonImport.Fields[j].table) {
objectArray[selectedObject].Fields.push({
"field": jsonImport.Fields[j].field,
"type": jsonImport.Fields[j].type
});
}
}
}
console.log(objectArray);
outputting:-

Categories