I have a JSON object as follows,
x = {
"prop1": {
"description": "prop1",
"dataType": "string",
"value" : "abc"
},
"prop2": {
"sub1": {
"description": "sub1",
"dataType": "integer",
"value" : 12
},
"sub2": {
"description": "sub2",
"dataType": "integer",
"value" : 15
}
},
"prop3": {
"input": {
"name": {
"description": "Whether to validate input messages",
"dataType": "boolean",
"value": false
}
},
"output": {
"description": "Whether to validate output messages",
"dataType": "boolean",
"value": false
}
}
}
I need to convert this object as below.
y = {
"prop1": "abc",
"prop2.sub1" :12,
"prop2.sub2" : 15,
"prop3.input.name" : false,
"prop3.output" : false,
}
I have to create the key name with "." in between prop and sub prop. need to write a recursive function. Any ideas on how to write the recursive function for this?
my code for this.
propPrefix = '';
y = {};
function createObject(props){
Object.keys(props).forEach(prop => {
const obj = props[prop];
const hasChildObject = Object.keys(obj).find(key => typeof(obj[key]) == 'object');
if(hasChildObject){
propPrefix = propPrefix == "" ? prop + '.' : (propPrefix + '.' + prop);
createObject(obj);
}else{
const value = obj.value;
y[propPrefix + prop] = value;
}
})
}
Here is a recursive solution for your problem. I go through each key of the object in each function call and stop if I find a key named value, store it in the obj1 variable
x = {
"prop1": {
"description": "prop1",
"dataType": "string",
"value" : "abc"
},
"prop2": {
"sub1": {
"description": "sub1",
"dataType": "integer",
"value" : 12
},
"sub2": {
"description": "sub2",
"dataType": "integer",
"value" : 15
}
},
"prop3": {
"input": {
"name": {
"description": "Whether to validate input messages",
"dataType": "boolean",
"value": false
}
},
"output": {
"description": "Whether to validate output messages",
"dataType": "boolean",
"value": false
}
}
}
function findValue(obj, string, obj1) {
if (obj.hasOwnProperty("value")) {
obj1[string.substring(1)] = obj.value
return
}
for (var key in obj) {
findValue(obj[key], [string, key].join("."), obj1)
}
}
var y = {}
findValue(x, "", y)
console.log(y)
Result is of the desired format
{ prop1: 'abc',
'prop2.sub1': 12,
'prop2.sub2': 15,
'prop3.input.name': false,
'prop3.output': false }
Related
I have an array of json objects like below. Each object has permanent key 'type' and depending on the 'type', new keys are added.
So if type: 'text', we have a new key 'text'.
If type: 'notText', we have a new key 'attrs'.
arrayOfObj = [
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
}
]
Depending on the 'type' of each item i.e. if type: 'text', then I need to combine each 'text' into 1 object like so:
arrayOfObj = [
{
"type": "text",
"text": "= SO"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
}
]
I know that to start it I can use
if(this.arrayOfObj.map(ed=>ed.type) === 'text') {
Object.assign({}, ...arrayOfObj);
}
However it doesn't quite work and I'm unsure of how to go further.
Would anyone have any idea of how to accomplish this?
Example below.
const arrayOfObj = [ { type: "text", text: "=", }, { type: "text", text: " ", }, { type: "text", text: "S", }, { type: "text", text: "O", }, { type: "notText", attrs: { id: 20, data: "Something", }, }, ];
const output = arrayOfObj.reduce(
(a, b) => {
if (b.type === "text") {
a[0].text += b.text;
} else {
a.push({
type: b.type,
attrs: b.attrs,
});
}
return a;
},
[{ type: "text", text: "" }]
);
console.log(output);
You can use reduce method to do this.
arrayOfObj = [{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
},
{
"type": "notText",
"attrs": {
"id": 22,
"data": "Something",
}
}
]
const t = arrayOfObj.reduce((acc, curr) => {
if (curr.type === "text") {
const accTypeText = acc.find((v) => v.type === "text");
if (accTypeText) {
accTypeText.text += curr.text;
return [...acc];
}
}
return [...acc, curr];
}, [])
console.log(t);
Note: the map method return an array, so your if statement return always false
We can use Array.reduce to create the desired object from the arrayOfObj input, if it is of type 'text' concatenate, otherwise just set the attrs.
const arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } }, { "type": "someOtherType", "attrs": { "id": 35, "data": "Something else", } } ]
const result = Object.values(arrayOfObj.reduce((acc, { type, text, attrs }) => {
if (!acc[type]) acc[type] = { type };
if (type === 'text') acc[type].text = (acc[type].text || '') + text;
if (type !== 'text') acc[type].attrs = attrs;
return acc;
}, {}));
console.log('Result:', result)
I am breaking the problem step by step, I would do this:
let arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } } ]
let completeString = "";
arrayOfObj.forEach(x => x.type == "text" ? completeString += x.text : "")
arrayOfObj = arrayOfObj.filter(x => x.type == "notText");
arrayOfObj.push({ "type": "text", "text": completeString })
console.log(arrayOfObj);
This is how I would do it. A similar idea to #R3tep &#ikhvjs's answers using reduce, only much less elegant.
const arrayOfObj = [ { type: "text", text: "=", }, { type: "text", text: " ", }, { type: "text", text: "S", }, { type: "text", text: "O", }, { type: "notText", attrs: { id: 20, data: "Something", }, }, ];
function combineTexts(arrayOfObj) {
let noTextArray = arrayOfObj.filter(i => i.type !== 'text');
let allTexts = arrayOfObj.filter(i => i.type === 'text')
.map(i => i.text)
.reduce((a, b) => a + b, '');
noTextArray.unshift({ type: 'text', text: allTexts });
return noTextArray;
}
console.log(combineTexts(arrayOfObj))
I am working on parsing a JSON and searching for specific key in that JSON object. The problem is that the structure of JSON keeps changing and i cannot hard code the path, is there any better ways to parse?
or
can i get this to convert in to regular JSON key value pairs as below
{
"resourceName": "Bundle",
"id": "6d6e-81d5-5a1e2b452563",
"lastUpdated": "2069-06-21",
"url": "http://abcd.com",
.
.
.
... so on
}
I have tried using hard coded methods but that doesnt seem to work always
Here is snipped of JSON
{
"resourceName": "Bundle",
"id": "6d6e-81d5-5a1e2b452563",
"meta": {
"lastUpdated": "2069-06-21"
},
"data1": [{
"url": "http://abcd.com",
"value": {
"url": "http://abcd.com",
"value": [{
"url": "Severity",
"value": "info"
}, {
"url": "dfew",
"value": "fefdd"
}, {
"url": "fwef",
"value": "This is data blah blah"
}]
}
}]
}
You search the object recursively:
function get_lastUpdated(obj)
{
for ( var key in obj )
{
if ( key == "lastUpdated" ) return obj[key];
if ( typeof obj[key] == "object" )
{
var res = get_lastUpdated(obj[key]);
if ( res ) return res;
}
}
return null;
}
For a simple case, something like above could work.
When you call JSON.parse, you can pass in a callback function, called a reviver, which will be recursively applied to all key-value pairs. For example:
var jsonString = `{
"resourceName": "Bundle",
"id": "6d6e-81d5-5a1e2b452563",
"meta": {
"lastUpdated": "2069-06-21"
},
"data1": [{
"url": "http://abcd.com",
"value": {
"url": "http://abcd.com",
"value": [{
"url": "Severity",
"value": "info"
}, {
"url": "dfew",
"value": "fefdd"
}, {
"url": "fwef",
"value": "This is data blah blah"
}]
}
}]
}`;
var obj = {};
JSON.parse(jsonString, (key, value) => {
if (typeof value === "string" && !(key in obj)) {
obj[key] = value;
}
});
console.log(obj);
If have already parsed the object, you can use a similar strategy with JSON.stringify and the replacer callback:
var data = {
"resourceName": "Bundle",
"id": "6d6e-81d5-5a1e2b452563",
"meta": {
"lastUpdated": "2069-06-21"
},
"data1": [{
"url": "http://abcd.com",
"value": {
"url": "http://abcd.com",
"value": [{
"url": "Severity",
"value": "info"
}, {
"url": "dfew",
"value": "fefdd"
}, {
"url": "fwef",
"value": "This is data blah blah"
}]
}
}]
};
var obj = {};
JSON.stringify(data, (key, value) => {
if (typeof value === "string" && !(key in obj)) {
obj[key] = value;
}
return value;
});
console.log(obj);
I have a JSON file like(for example) :
"fields": {
"asset": {
"values": [{
"asset": {
"id": "Info_text",
"type": "text",
"value": "ABCD"
}
},
{
"asset": {
"id": "Info_input",
"type": "input",
"value": "ABCDE"
}
}
]
}
}
How can I iterate over the values of "id" and check if they a unique or not in javascript?
here is complete demo without additional library, you can find if any key/value pair is unique in a json object and how many occurences were found :
var jsonData = {
"fields": [
{
"asset": {
"id": "Info_input",
"values": [
{
"asset": {
"id": "Info_text",
"type": "text",
"value": "ABCD"
}
},
{
"asset": {
"id": "Info_input",
"type": "input",
"value": "ABCDE"
}
},
{
"asset": {
"id": "Info_input",
"type": "input",
"value": "ABCDE"
}
}
]
}
}
]
}
function findKeyValueCount(key, value, obj) {
var count = 0;
var keys = Object.keys(obj);
keys.forEach(function(k) {
var v = obj[k];
if(typeof v === 'object') {
count += findKeyValueCount(key, value, v)
}
else if(k === key && v === value) {
count += 1;
}
});
return count;
}
function isUnique(key, value, obj) {
return findKeyValueCount(key, value, obj) === 1;
}
console.log(findKeyValueCount('id', 'Info_text', jsonData));
// -> 1
console.log(findKeyValueCount('id', 'Info_input', jsonData));
// -> 3
console.log(findKeyValueCount('value', 'ABCDE', jsonData));
// -> 2
console.log(findKeyValueCount('xxx', 'yyy', jsonData));
// -> 0
console.log(isUnique('id', 'Info_input', jsonData));
// -> false
console.log(isUnique('id', 'Info_text', jsonData));
// -> true
Have fun !
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)));
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:-