Reputation: 3051
I have this json:
[
{
"question": "1.1",
"level": 1,
"id": 4,
"answers": [
{
"text_answer": "NO",
"questions": [
{
"question": "1.1.1",
"level": 2,
"id": 3,
"answers": []
}
]
},
{
"text_answer": null,
"questions": [
{
"question": "1.1.2",
"level": 2,
"id": 2,
"answers": [
{
"text_answer": "SI",
"questions": [
{
"question": "1.1.2.1",
"level": 3,
"id": 1,
"answers": []
}
]
}
]
}
]
}
]
}
]
this json
is dynamic and can have n
amount of levels under the fields answers
and questions
that is why it is necessary to go through them with a recursive
function
I want to get this output:
[
{
"question": "1.1",
"level": 1,
"id": 4,
"children": [
{
"question": "1.1.1",
"text_answer": "NO",
"level": 2,
"id": 3,
"children": []
},
{
"question": "1.1.2",
"text_answer": null,
"level": 2,
"id": 2,
"children": [
{
"question": "1.1.2.1",
"text_answer": "SI",
"level": 3,
"id": 1,
"children": []
}
]
}
]
}
]
the fields answers
and questions
no longer exist, they are renamed children
and the content of both is unified.
I think this recursive
function should do a double foreach
, but I don't know how to do it.
function format(d) {
if (d.respuestas) {
d.respuestas.forEach((d) => {
format;
});
}
}
format(data);
var data= [
{
"question": "1.1",
"level": 1,
"id": 4,
"answers": [
{
"text_answer": "NO",
"questions": [
{
"question": "1.1.1",
"level": 2,
"id": 3,
"answers": []
}
]
},
{
"text_answer": null,
"questions": [
{
"question": "1.1.2",
"level": 2,
"id": 2,
"answers": [
{
"text_answer": "SI",
"questions": [
{
"question": "1.1.2.1",
"level": 3,
"id": 1,
"answers": []
}
]
}
]
}
]
}
]
}
]
/* [
{
"question": "1.1",
"level": 1,
"id": 4,
"children": [
{
"question": "1.1.1",
"text_answer": "NO",
"level": 2,
"id": 3,
"children": []
},
{
"question": "1.1.2",
"text_answer": null,
"level": 2,
"id": 2,
"children": [
{
"question": "1.1.2.1",
"text_answer": "SI",
"level": 3,
"id": 1,
"children": []
}
]
}
]
}
]
*/
function format(d) {
if (d.answers) {
d.answers.forEach((d) => {
format;
});
}
}
format(data);
**note:**
I changed the previous structure that I put to the question to make myself understand better.
Upvotes: 2
Views: 233
Reputation: 14537
It works for me:
// here is your JSON
var json = [{
"question": "1.1",
"level": 1,
"id": 4,
"answers": [{
"text_answer": "NO",
"questions": [{
"question": "1.1.1",
"level": 2,
"id": 3,
"answers": []
}]
},
{
"text_answer": null,
"questions": [{
"question": "1.1.2",
"level": 2,
"id": 2,
"answers": [{
"text_answer": "SI",
"questions": [{
"question": "1.1.2.1",
"level": 3,
"id": 1,
"answers": []
}]
}]
}]
}
]
}]
// main
function change(branch) {
// the first level has a bit different structure
try {
if (branch.level == 1) {
return {
question: branch.question,
level: branch.level,
id: branch.id,
children: change(branch.answers)
}
}
} catch (e) {}
// next levels
var new_branch = [];
for (var i = 0; i < branch.length; i++) {
new_branch.push({
question: branch[i].questions[0].question,
text_answer: branch[i].text_answer,
level: branch[i].questions[0].level,
id: branch[i].questions[0].id,
children: [change(branch[i].questions[0].answers)].flat(1)
});
}
return new_branch;
}
// output
console.log(JSON.stringify(change(json[0])));
Upvotes: 0
Reputation: 7548
Here is one approach via recurssion. I've commented the code to explain what exactly is going on line by line.
function _process(item) {
let result = item // we define a copy of item -> result
// this is renaming the field 'answers' (if found)
if (item.answers) {
result.children = item.answers.map(_process) // process each item separately
delete result.answers
}
// if there is a question field, extract the first item in the array and merge the attributes with result
if (item.questions) {
result = {
...result,
..._process(item.questions[0]) // also try to process the item before merging it (to check if there are nested 'questions' or 'answers' fields)
}
delete result.questions // remove the questions field
}
return result
}
function process(data) {
return data.map(_process) // start the recurssion for top-level objects
}
// sample data to test out
const data = [{
"question": "1.1",
"level": 1,
"id": 4,
"answers": [{
"text_answer": "NO",
"questions": [{
"question": "1.1.1",
"level": 2,
"id": 3,
"answers": []
}]
},
{
"text_answer": null,
"questions": [{
"question": "1.1.2",
"level": 2,
"id": 2,
"answers": [{
"text_answer": "SI",
"questions": [{
"question": "1.1.2.1",
"level": 3,
"id": 1,
"answers": []
}]
}]
}]
}
]
}]
const result = process(data)
console.log(JSON.stringify(result, null, 2))
Upvotes: 6
Reputation: 11812
You're on the right track in writing a recursive function.
Where I think you're going wrong is in thinking about 'pushing' it to an array or object to store the data.
Instead, what should happen is that your recursive function returns the formatted data, and then that data is added to new json object which is sent back up the call stack.
var data = {
"name": "1.question",
"answer": "YES",
"children": [{
"name": "1.1 question",
"answer": "yes"
},
{
"name": "1.2 question",
"answer": "NO",
"children": [{
"name": "1.2.1 question",
"answer": "NO"
}]
},
{
"name": "1.3 question",
"answer": "YES",
"children": [{
"name": "1.3.1 question",
"answer": "yes",
"children": [{
"name": "1.3.1.1 question",
"answer": "YES"
}]
}]
}
]
}
function format(d) {
if (d.children) {
// if there are children you are going to recurse deeper
// use the Array.prototype.map function to _transform_ each of the children.
const formattedChildren = d.children.map(v => {
return format(v);
});
// Notice that I'm returning a new object here, as well as
// An aggregation of the already transformed data
return {
data: "new formatted parent node data goes here",
children: formattedChildren
};
} else { // _always_ have a check for 'is it a leaf node'.
// If it's a leaf node node, just format it.
//Notice that I'm returning a new object here
return {
data: "new formatted leaf node data goes here"
};
}
}
console.log(format(data));
I don't know what you are trying to achieve, so I've left this blank. But this is the template for how you would recursively traverse and transform a nested object like this.
(Note that you don't need to have a data
key, I've just put that in as a place holder. It looks like you want name
and answered
keys.
Upvotes: 1