Convert array in to specific format recursively - javascript

I have one array that contains hierarchical data, i wan to convert it to hierarchy but in different format. I tried to use recursive method but its not giving proper data
Below is my code what i tried to implement
static convertConfigJson(data, finalResults = []) {
const configData = JSON.parse(JSON.stringify(data));
return configData.map((item) => {
const { name, type, value, path } = item;
let children = {}
if (type === 'Object') {
children = this.convertConfigJson(value, finalResults);
} else {
finalResults.push({
id: name,
name: name,
children: children
})
}
console.log('>>>>>>>>>', finalResults)
return finalResults;
});
}
Below is JSON array that i am getting from API
[
{
"name": "info",
"type": "Object",
"value": [
{
"name": "app",
"type": "Object",
"value": [
{
"path": "info.app",
"name": "encoding",
"type": "TEXT",
"value": "#project.build.sourceEncoding#"
},
{
"name": "java",
"type": "Object",
"value": [
{
"path": "info.app.java",
"name": "source",
"type": "TEXT",
"value": "#java.version#"
},
{
"path": "info.app.java",
"name": "target",
"type": "TEXT",
"value": "java.version#"
}
]
}
]
}
]
}
]
I want to convert above array in below format i.e. change value array to children
[
{
"name": "info",
"type": "Object",
"children": [
{
"name": "app",
"type": "Object",
"children": [
{
"path": "info.app",
"name": "encoding",
"type": "TEXT",
"value": "#project.build.sourceEncoding#"
},
{
"name": "java",
"type": "Object",
"children": [
{
"path": "info.app.java",
"name": "source",
"type": "TEXT",
"value": "#java.version#"
},
{
"path": "info.app.java",
"name": "target",
"type": "TEXT",
"value": "java.version#"
}
]
}
]
}
]
}
]

Simple recursive walk on all elements in children property. set .value to .children and delete .value
walk = node => {
if(!node.value || typeof node.value!=='object') return
node.children = node.value
delete node.value
node.children.forEach(walk)
}
data.forEach(walk)
console.log(data)
<script>
data=[
{
"name": "info",
"type": "Object",
"value": [
{
"name": "app",
"type": "Object",
"value": [
{
"path": "info.app",
"name": "encoding",
"type": "TEXT",
"value": "#project.build.sourceEncoding#"
},
{
"name": "java",
"type": "Object",
"value": [
{
"path": "info.app.java",
"name": "source",
"type": "TEXT",
"value": "#java.version#"
},
{
"path": "info.app.java",
"name": "target",
"type": "TEXT",
"value": "java.version#"
}
]
}
]
}
]
}
]
</script>

write transform method, When ever object has the "value" type is Array then call the transform recursively.
const transform = ({ value, ...rest }) => {
const item = { ...rest };
Array.isArray(value)
? (item["children"] = value.map(transform))
: (item["value"] = value);
return item;
};
// Update: Based on #user120242 suggestion, creating another object is not required and using `Object.assign` will simplify.
const transform2 = ({ value, ...rest }) =>
Object.assign(
rest,
Array.isArray(value) ? { children: value.map(transform2) } : { value }
);
const items = [
{
name: "info",
type: "Object",
value: [
{
name: "app",
type: "Object",
value: [
{
path: "info.app",
name: "encoding",
type: "TEXT",
value: "#project.build.sourceEncoding#",
},
{
name: "java",
type: "Object",
value: [
{
path: "info.app.java",
name: "source",
type: "TEXT",
value: "#java.version#",
},
{
path: "info.app.java",
name: "target",
type: "TEXT",
value: "java.version#",
},
],
},
],
},
],
},
];
const output = items.map(transform);
console.log(output);
console.log(items.map(transform2));

This technique is similar to the answer from user120242, but it does not mutate your input structure, creating a new one instead:
const transform = ({value, ...rest}) =>
Array .isArray (value)
? {...rest, children: value .map (transform)}
: {...rest, value}
const data = [{name: "info", type: "Object", value: [{name: "app", type: "Object", value: [{path: "info.app", name: "encoding", type: "TEXT", value: "#project.build.sourceEncoding#"}, {name: "java", type: "Object", value: [{path: "info.app.java", name: "source", type: "TEXT", value: "#java.version#"}, {path: "info.app.java", name: "target", type: "TEXT", value: "java.version#"}]}]}]}]
console .log (data .map (transform))
Update
Borrowing a technique from sivako, we can simplify this nicely:
const transform = ({value, ...rest}) => ({
... rest,
... (Array .isArray (value) ? {children: value .map (transform)} : {value})
})
const data = [{name: "info", type: "Object", value: [{name: "app", type: "Object", value: [{path: "info.app", name: "encoding", type: "TEXT", value: "#project.build.sourceEncoding#"}, {name: "java", type: "Object", value: [{path: "info.app.java", name: "source", type: "TEXT", value: "#java.version#"}, {path: "info.app.java", name: "target", type: "TEXT", value: "java.version#"}]}]}]}]
console .log (data .map (transform))

An easiest way is just replace all "value": [ to "children": [ after stringify
function convertConfigJson(data) {
const configData = JSON.parse(JSON.stringify(data).replace(/"value":\[/g, '"children":['));
return configData
}
also you can go one by one through all keys of nested object, and replace value keys with array in value to children

Related

Removing a specific element from an object that is located inside a parent element

I have the following object:
const jj = {
"type": "doc",
"content": [{
"type": "paragraph",
"content": [{
"type": "text",
"text": "HI \n"
}, {
"type": "text",
"marks": [{
"type": "link",
"attrs": {
"href": "https://infosysta-my.sharepoint.com/:x:/p/elie%5Fiskandar/EXmik99OQBBNiJua1zbbiUIBwU8QEVOzyXl3qRV3ZnhADw",
"__confluenceMetadata": null
}
}],
"text": "Client List - MW.xlsx"
}]
}, {
"type": "paragraph",
"content": [{
"type": "text",
"text": "regards,"
}]
}],
"version": 1
};
I need to remove the "__confluenceMetadata":null key/value so the new object will be:
const jj = {
"type": "doc",
"content": [{
"type": "paragraph",
"content": [{
"type": "text",
"text": "HI \n"
}, {
"type": "text",
"marks": [{
"type": "link",
"attrs": {
"href": "https://infosysta-my.sharepoint.com/:x:/p/elie%5Fiskandar/EXmik99OQBBNiJua1zbbiUIBwU8QEVOzyXl3qRV3ZnhADw"
}
}],
"text": "Client List - MW.xlsx"
}]
}, {
"type": "paragraph",
"content": [{
"type": "text",
"text": "regards,"
}]
}],
"version": 1
};
I tired to iterate through the elements using let arr = Object.entries(ADFDocJson); but I couldn't reach what I needed.
I am looking for a generic method to use as this is just an example object and there might be multiple objects in the marks array.
Presented below is one possible way to achieve the desired objective.
Code Snippet
const removeMeta = argObj => (
Object.fromEntries(
Object.entries(argObj)
.map(([k, v]) => (
k !== 'content'
? ([k, v])
: ([k, (
v.map(ob1 => (
!('content' in ob1)
? ({...ob1})
: ({...ob1,
content: ob1.content.map(
ob2 => (
!('marks' in ob2)
? ({ ...ob2 })
: ({ ...ob2,
marks: ob2.marks.map(ob3 => (
!('attrs' in ob3 &&
'__confluenceMetadata' in ob3.attrs &&
ob3.attrs['__confluenceMetadata'] === null
)
? ({ ...ob3 })
: ({ ...ob3,
attrs: Object.fromEntries(
Object.entries(ob3.attrs)
.filter(
(
[k2, v2]
) => (
k2 !== '__confluenceMetadata'
)
)
)
})
))
})
)
)
})
))
)])
))
)
);
const jj = {
"type": "doc",
"content": [{
"type": "paragraph",
"content": [{
"type": "text",
"text": "HI \n"
}, {
"type": "text",
"marks": [{
"type": "link",
"attrs": {
"href": "https://infosysta-my.sharepoint.com/:x:/p/elie%5Fiskandar/EXmik99OQBBNiJua1zbbiUIBwU8QEVOzyXl3qRV3ZnhADw",
"__confluenceMetadata": null
}
}],
"text": "Client List - MW.xlsx"
}]
}, {
"type": "paragraph",
"content": [{
"type": "text",
"text": "regards,"
}]
}],
"version": 1
};
console.log(removeMeta(jj));
.as-console-wrapper { max-height: 100% !important; top: 0 }
Explanation
Iterate over the various key-value pairs of the object, and then iterate over the nested 'content' arrays, identify the relevant prop and filter it out.

How to group an array of objects in javascript?

I'm trying to group an array of objects. The array should be grouped following this quote:
Group by type respecting the sequence.
Array I wish to group
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
The way I want it to be grouped:
var newArray = [
[
{type: "user", text: "user1"},
{type: "user", text: "user2"},
{type: "user", text: "user3"}
],
[
{type: "clerk", text: "clerk1"}
],
[
{type: "user", text: "user4"}
],
[
{type: "clerk", text: "clerk2"},
{type: "clerk", text: "clerk3"}
],
[
{type: "user", text: "user5"},
{type: "user", text: "user6"}
]
];
What i tried:
I'm trying to use a filter, but without success since it even groups, but it groups all that are of the same type without respecting the sequence I want (from the array above);
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
var newArray = [];
newArray.push(filtrarArray(arrayObj, 'clerk'));
newArray.push(filtrarArray(arrayObj, 'user'));
console.log(newArray);
function filtrarArray(array, type) {
return array.filter(function (val) {
return val.type === type;
});
}
The snippet below first sorts the array by type, which then makes it easy to loop through and group. Let me know if this solves your problem :)
EDIT
Just realized you didn't need sorting, so I commented the sort function out, but it's always there to be uncommented if you change your mind :)
const arrayObj = [
{ type: 'user', text: 'user1' },
{ type: 'user', text: 'user2' },
{ type: 'user', text: 'user3' },
{ type: 'clerk', text: 'clerk1' },
{ type: 'user', text: 'user4' },
{ type: 'clerk', text: 'clerk2' },
{ type: 'clerk', text: 'clerk3' },
{ type: 'user', text: 'user5' },
{ type: 'user', text: 'user6' },
];
const group = ar =>
ar
// .sort((a, b) => (a.type < b.type ? -1 : 1))
.reduce((newAr, obj, i) => {
if (0 === i) return [[obj]];
if (obj.type === newAr[newAr.length - 1][0].type)
return newAr[newAr.length - 1].push(obj), newAr;
return [...newAr, [obj]];
}, []);
const groupedAr = group(arrayObj);
console.log(groupedAr);
function groupConsecutive(arrayObj) {
if (arrayObj.length === 0) {
return [];
}
let matchedTypesIndex = 0;
let newArray = [
[
arrayObj[0]
]
];
let currentType = arrayObj[0]["type"];
let i = 1;
while (i < arrayObj.length) {
if (arrayObj[i]["type"] === currentType) {
newArray[matchedTypesIndex].push(arrayObj[i]);
} else {
currentType = arrayObj[i]["type"];
newArray.push([]);
matchedTypesIndex++;
newArray[matchedTypesIndex].push(arrayObj[i]);
}
i++;
}
return newArray;
}
This is probably not best pure solution but works as you need.
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let lastType;
let arr = [];
let arrIndex = -1;
arrayObj.forEach(obj => {
if(obj.type == lastType) { // add item into last group array by index
arr[arrIndex].push(obj);
}
else { // or add new group array
lastType = obj.type;
arrIndex++;
arr.push([obj]);
}
})
console.log(arr);
See This solution it will work
var arrayObj = [
{ type: "user", text: "user1" },
{ type: "user", text: "user2" },
{ type: "user", text: "user3" },
{ type: "clerk", text: "clerk1" },
{ type: "user", text: "user4" },
{ type: "clerk", text: "clerk2" },
{ type: "clerk", text: "clerk3" },
{ type: "user", text: "user5" },
{ type: "user", text: "user6" },
];
let typeNow = arrayObj[0].type;
let res = [];
let resultArray = [];
arrayObj.forEach((obj, i) => {
if (obj.type == typeNow) {
resultArray.push(obj);
} else {
resultArray = [obj];
res.push(resultArray);
typeNow = obj.type;
}
if (i == arrayObj.length - 1) res.push(resultArray);
});
console.log(res);
This is best solution can i have
It seem unordred because of Browser auto order but if you try in js file it will work and ordred
I'm responding with another way I found to solve my problem. This is just one more way I decided to comment.
Let's go:
I'm traversing the arrayObjects array using the appropriate loop for arrays for...of and then checking if the variable I set for arrayObjects (loopArrObj) has a different value of type of the variable (typeValue), if it is inserted at the end of the new array (grouping) using the array method push an empty array and then assign the value of the loopArrObj(Ie, there will be in the array grouping array empty only for the values ​​that are different).
So far so good, we have the first empty array. Next I'm defining this empty array with the push method the loopArrObj object in question, then we get the value through the console. I'm removing 1 from grouping.lengh so the loop assigns from 0 and not 1.
var arrayObjects = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let typeValue,
grouping = [],
loopArrObj;
for (loopArrObj of arrayObjects) {
if (loopArrObj.type !== typeValue) {
grouping.push([]);
typeValue = loopArrObj.type;
}
grouping[grouping.length - 1].push(loopArrObj);
}
console.log(grouping);

How to sort an array of object depending on value of a subfield?

I have an array of objects called posts with a nested field answer. I have different conditions depending on which I need to sort my array.
Example array
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "text",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "video",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "text",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "audio",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
What I need to do is...I want to sort all the answers with type "video" to start and after that type "audio" and then type "text" answers like so
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "video",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "text",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "audio",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "text",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
Any help would be appreciated. Thank you
You will need to loop through each entry in your posts array and sort the answers array inside each entry using a custom function.
The return value of the custom function (ele1, ele2) => {} should return a value > 0 if ele1 should be placed after ele2, a value < 0 if ele1 should be placed before ele2, and a value = 0 if they are considered equal.
const getRanking = (ele) => {
if (ele.type == "video") return 1;
if (ele.type == "audio") return 2;
if (ele.type == "text") return 3;
};
posts = posts.map(post => {
post.answers.sort((ele1, ele2) => {
return getRanking(ele1) - getRanking(ele2);
});
return post;
});
You should use lodash for this. Check out _.orderBy() method. Here is a helpful link: https://www.geeksforgeeks.org/lodash-_-orderby-method/
You need to add custom compare function.
This is the simplest solution for your question
let posts = [
{
"_id": "610b806ec6386ffa276b6d1c",
"post": "CDat the difference between Equity and News channel?",
"answers": [
{
"_id": "613724604dd4b6f39b344b4c",
"type": "text",
},
{
"_id": "6113c826a64da80fe48ab543",
"type": "video",
},
{
"_id": "6113c740a64da80fe48ab534",
"type": "audio",
},
{
"_id": "611135cf7497d70b6cc2c5e0",
"type": "video",
}
]
},
{
"_id": "611e14329ff0c343540ae10e",
"post": "How forex affects investment 6",
"answers": [
{
"_id": "61371b3a9bf14a39207fff8a",
"type": "video",
},
{
"_id": "613719369507fd12f93e3c62",
"type": "text",
},
{
"_id": "6135f28e29aeae3de45fc8c2",
"type": "text",
},
{
"_id": "6135f07c831da33c28fc1cf6",
"type": "audio",
},
{
"_id": "6135eb2d51a8830698d65cf3",
"type": "text",
},
]
}
]
function type (t){
if(t==="video") return 1;
if(t==="audio") return 2;
if(t==="text")return 3;
}
function comparotor(a, b){
return type(a.type) - type(b.type)
}
posts.map(ele=>{
ele.answers.sort(comparotor);
})
console.log(posts);
You can easily achieve the result by using JS only by passing the comparator function to sort function
"video" => "v"
"audio" => "a"
"text" => "t"
You can use indexOf to check the first letter in a list of sorted letters(vat)
posts.map((o) =>o.answers.sort((a, b) => "vat".indexOf(a.type[0]) - "vat".indexOf(b.type[0])))
let posts = [
{
_id: "610b806ec6386ffa276b6d1c",
post: "CDat the difference between Equity and News channel?",
answers: [
{
_id: "613724604dd4b6f39b344b4c",
type: "text",
},
{
_id: "6113c826a64da80fe48ab543",
type: "video",
},
{
_id: "6113c740a64da80fe48ab534",
type: "audio",
},
{
_id: "611135cf7497d70b6cc2c5e0",
type: "video",
},
],
},
{
_id: "611e14329ff0c343540ae10e",
post: "How forex affects investment 6",
answers: [
{
_id: "61371b3a9bf14a39207fff8a",
type: "video",
},
{
_id: "613719369507fd12f93e3c62",
type: "text",
},
{
_id: "6135f28e29aeae3de45fc8c2",
type: "text",
},
{
_id: "6135f07c831da33c28fc1cf6",
type: "audio",
},
{
_id: "6135eb2d51a8830698d65cf3",
type: "text",
},
],
},
];
const result = posts.map((o) =>o.answers.sort((a, b) => "vat".indexOf(a.type[0]) - "vat".indexOf(b.type[0])));
console.log(result);

Is it possible to add additional property to to filtered objects from an array of objects?

I have an object like this :
{
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
I want to re-organize the roleClaims array [ like each unique types objects (value = "Permissions.Brands.View" > Brands ) are separated array ] as mentioned below. And additionally add an extra property checkboxId (which value is unique number) to filtered object from the array of objects.
Is is really possible?
{
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"valueId": "a8ca7eac-4f18-42d6-983f-44f6a8e157dc",
"valueType": "Brands",
"valueArray": [
{
"checkboxId": uuidv4(), // create new unique id
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
}
]
},
{
"valueId": "a2566fd4-8763-41d4-881e-029851a440fd",
"valueType": "Dashboard",
"valueArray": [
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
}
]
},
{
"valueId": "72328955-2bd2-469c-a094-be0bba383edd",
"valueType": "Users",
"valueArray": [
{
"checkboxId": uuidv4(),,
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
]
}
I tried with this :
const getRoleDetailsByRoleId = roleId => {
axios.get(`${urls.account.permissions.get_all_by_roleId}?roleId=${roleId}`).then(res => {
const permissionData = res.data;
const splitedValues = [];
permissionData.roleClaims.forEach(item => splitedValues.push(item.value.split('.')[1]));
const uniqueValues = [...new Set(splitedValues)];
const modifiePermissiondObj = {
roleId: permissionData.roleId,
roleClaims: uniqueValues.map(item => ({
valueId: uuidv4(),
valueType: item,
valueArray: permissionData.roleClaims.filter((fileredItem, index, arr) => fileredItem.value.split('.')[1] === item)
}))
};
setPermissions(modifiePermissiondObj);
setIsPageLoaded(true);
});
};
I have modified the roleClaims array but can't add the additional property.
If possible please help me.
const permissionData = {
"roleId": "75f6af0f-a483-4ad1-af5f-5802887fe5e6",
"roleClaims": [
{
"type": "Permissions",
"value": "Permissions.Brands.View",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Brands.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Dashboard.Create",
"selected": false
},
{
"type": "Permissions",
"value": "Permissions.Users.Create",
"selected": false
}
]
}
const transformedPermissionData = permissionData.roleClaims.reduce((newOutput, role) => {
const extractedRole = role.value.split('.')[1];
const roleIndex = newOutput.roleClaims.findIndex(output => output && output.valueType === extractedRole)
if(roleIndex !== -1){
newOutput.roleClaims[roleIndex].valueArray.push({...role, checkboxId: 'UUID'})
}else {
newOutput.roleClaims.push({
valueId: 'UUID',
valueType: extractedRole,
valueArray: [{...role, checkboxId: 'UUID'}]
})
}
return newOutput
}, { roleId: permissionData.roleId, roleClaims: []})
console.log(transformedPermissionData)
You just need to map your valueArray like this:
valueArray: permissionData.roleClaims
.filter((fileredItem, index, arr) => fileredItem.value.split('.')[1] === item)
.map(value => ({...value, checkboxId: uuidv4()}))

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.

Categories