I am building a JSON file dynamically. I want to add a JSON array in the JSON object. The JSON looks like-
{"name":"Root",
"children":[
{"name":"child1"},
{"name":"child2"}
]}
Now, I want to add -
[{"name":"child11"},{"name":"child12"}]
under "child1" object. How to do it? I have also tried keeping blank children object while creating the original JSON object, but JSON parser doesn't keep those empty children block. In current scenario, when I am using push() function to add new child it throws exception. Any help is much appreciated.
Thanks in advance!!
Edit1: I think I didn't made myself clear enough. I have researched SO before posting this question, and I guess this is not a duplicate question. My target JSON is -
{
"name": "Root",
"children": [{
"name": "child1",
"children": [{
{"name": "child11"},
{"name": "child12"}
}]
},
{
"name": "child2",
"children": [{
{"name": "child21"},
{"name": "child22"}
}]
}
]
};
Here is the code snippet that I am trying to run -
flare = {
"name": "Root",
"children": [{
"name": "child1",
"children": [{
{"name": "child11"},
{"name": "child12"}
}]
},
{
"name": "child2",
"children": [{
{"name": "child21"},
{"name": "child22"}
}]
}
]
};
var updatedJson = twoLevelSelection(flare);
function twoLevelSelection(json){
var root = flare.name;
var string_json = '';
string_json = '{"name": "'+root+'","children": [';
flare.children.forEach(
function(d){
string_json = string_json+ '{"name":"'+d.name+'","children":[]},';
}
);
string_json = string_json.substring(0,string_json.length-1);
string_json = string_json + ']}';
return JSON.parse(string_json);
}
// data is the original data.i.e - flare
// d is the clicked node, under which children to be added
function traverse(data,d){
var queue = [];
var next = data;
while(next){
if(next.children){
next.children.forEach(
function(k){
queue.push(k);
}
)
}
if(queue[0].name==d.name){
alert(queue[0].children);
//d.children = queue[0].children;
var child_string='';
var child_array = [];
queue[0].children.forEach(
function(j){
child_string = '{"name": "'+j.name+'"}';
child_array.push(child_string);
}
);
console.log(child_array);
d.children = [...child_array];
console.log(updatedJson);
//update(updatedJson);
break;
}else{
next= queue.shift();
}
}
}
The traverse() will be called on a click event.
Sorry, for not providing clarity at first place. Thanks!
You can use the Spread Operator to accomplish that.
This code snippet has a function called addElements which find the target and adds the new elements to the children array.
var obj = {
"name": "Root",
"children": [{
"name": "child1"
},
{
"name": "child2"
}
]
};
var newArray = [
{ "name": "child11"},
{ "name": "child12"}
];
var addElements = function(target, array) {
obj.children.forEach(function(child) {
if (child.name === target) {
child['children'] = [...(child['children'] || []), ...newArray];
return;
}
});
};
addElements('child1', newArray);
console.log(obj);
See? now your obj.childre[0].children array contains the new elements.
Related
I have a JSON array of the following format (this data is pulled from mongodb to be displayed as a tree graph on a react-based front-end):
[
{
"name": "7654321",
"children": [
{
"_id": "LjYgocn9PsHhEFbM7",
"accountId": "4343213"
},
{
"_id": "sB2ipCstYnLnHrAuu",
"accountId": "4343271"
},
{
"_id": "JhugmhxS7A57Y34wM",
"accountId": "4343276"
}
]
},
{
"name": "4343213",
"children": [
]
},
{
"name": "4343271",
"children": [
{
"_id": "sie9mtttgdRw7Ktma",
"accountId": "4343279"
}
]
},
{
"name": "4343279",
"children": [
{
"_id": "sie23mtttgdRw7Ktma",
"accountId": "8765345"
}
]
},
{
"name": "4343276",
"children": [
]
}
]
The goal is to re-format (rename and delete some keys) this data to be used in react-tree-graph. From the sample above, output should look like:
[
{
"name": "7654321",
"children": [
{
"name": "4343213"
},
{
"name": "4343271",
"children": [
{
"name": "4343279",
"children": [
{
"name": "8765345"
}
]
}
]
},
{
"name": "4343276"
}
]
}
]
Any help is appreciated!
You could first create a Map that has as keys the name property values, and as corresponding values the (unfinished) result objects. They start off with just the name property.
Then you can iterate the children information in the input, to wire the children into the above mentioned result objects, which can be done efficiently using the name as key in the Map.
Whenever you wire a child object into a parent object, you know that child is not a top-level object in the final result. So starting with all nodes, you would trim that list (a Set) all those nodes that occur in a children array. This will leave you with only the top level nodes, which in its array form represents the desired output.
Implementation:
let data = [{"name": "7654321","children": [{"_id": "LjYgocn9PsHhEFbM7","accountId": "4343213"},{"_id": "sB2ipCstYnLnHrAuu","accountId": "4343271"},{"_id": "JhugmhxS7A57Y34wM","accountId": "4343276"}]},{"name": "4343213","children": []},{"name": "4343271","children": [{"_id": "sie9mtttgdRw7Ktma","accountId": "4343279"}]},{"name": "4343279","children": [{"_id": "sie23mtttgdRw7Ktma","accountId": "8765345"}]},{"name": "4343276","children": []}];
let map = new Map(data.map(({name, children}) => [name, { name }]));
let roots = new Set(map.values());
for (let {name, children} of data) {
if (!children?.length) continue;
map.get(name).children = children.map(({accountId}) => {
let child = map.get(accountId) || { name: accountId };
roots.delete(child);
return child;
});
}
let result = Array.from(roots);
console.log(result);
I need to extract json and print it. At first I did manually but that's obviously not the right way. When I try to use forEach loop looped through got 3 object not sure what to do next. My question is is it possible to display data using only loops?
jsonDisplay = () => {
let data = `{
"name": "GI",
"size": 10,
"nodes": [
{
"name": "Mysterious",
"size": 2,
"nodes": [
{
"name": "Center",
"size": 1,
"nodes": [
{
"name": "Fisherman",
"size": 0.5,
"nodes": []
}
]
},
{
"name": "Dog",
"size": 1,
"nodes": []
}
]
},
{
"name": "Cat",
"size": 4,
"nodes": []
}
]
}
`
let json = JSON.parse(data);
let display = document.getElementById('json');
let display2 = document.getElementById('jsonloop');
console.log(json);
json.nodes.forEach(function(element) {
console.log(element);
});
display.innerHTML = `${json.name} ${json.size}
<br>
${json.name} - ${json.nodes[0].name} ${json.nodes[0].size}
<br>
${json.name} - ${json.nodes[0].name} - ${json.nodes[0].nodes[0].name} ${json.nodes[0].nodes[0].size}
<br>
${json.name} - ${json.nodes[0].name} - ${json.nodes[0].nodes[0].name} ${json.nodes[0].nodes[0].nodes[0].name} - ${json.nodes[0].nodes[0].nodes[0].size}
<br>
${json.name} - ${json.nodes[0].name} - ${json.nodes[0].nodes[1].name} - ${json.nodes[0].nodes[1].size}
<br>
${json.name} - ${json.nodes[1].name} - ${json.nodes[1].size}`;
}
jsonDisplay();
So you want to print out the name/size of each nested object? Here's a basic recursive function that will help.
const data = {"name":"GI","size":10,"nodes":[{"name":"Mysterious","size":2,"nodes":[{"name":"Center","size":1,"nodes":[{"name":"Fisherman","size":0.5,"nodes":[]}]},{"name":"Dog","size":1,"nodes":[]}]},{"name":"Cat","size":4,"nodes":[]}]};
(function recursivePrint({ name, size, nodes }) {
console.log(name, size);
nodes.length && nodes.forEach(node => recursivePrint(node));
})(data);
This is my array of objects:
I am using vue.js , I need a tree like this to keep the structure of tree view: https://v2.vuejs.org/v2/examples/tree-view.html
[
{
"name": "",
"children": []
},
{
"name": "",
"children": [
{
"name": "Leggi",
"children": []
}
]
},
{
"name": "",
"children": [
{
"name": "Leggi",
"children": [
{
"name": "2010",
"children": []
}
]
}
]
},
{
"name": "",
"children": [
{
"name": "Leggi",
"children": [
{
"name": "2011",
"children": []
}
]
}
]
},
{
"name": "",
"children": [
{
"name": "Titoli",
"children": []
}
]
}
]
I need a function to retrive an object grouped by name with his childrens
{
"name": "",
"children": [
{
"name": "Leggi",
"children": [
{
"name": "2010",
"children": []
},
{
"name": "2011",
"children": []
}
],
"name": "Titoli",
"children": []
}
]
}
I would like to know if there it is a simple way (instead of writing a recursive function), like using lodash or something near it.
Thanks
I think that i have implemented a more readable answer:
const rootTree = [];
const putInTree = (tree, node) => {
let nodeInTree = tree.find(x => x.name === node.name);
if (!nodeInTree) {
nodeInTree = {name: node.name, children: []};
tree.push(nodeInTree);
}
if (node.children[0]) putInTree(nodeInTree.children, node.children[0])
}
nodes.forEach(node => putInTree(rootTree, node));
nodes here is your start array, let me know if this is ok
treeArchive.forEach(element => {
element.children.forEach(father => {
if (result.children.length != 0) {
cicleChildrens(result, father);
function cicleChildrens(padrePrecedente, nuovoPadre){
var brother = padrePrecedente.children.find(x => x.name == nuovoPadre.name);
if (brother != undefined) cicleChildrens(brother, nuovoPadre.children[0]);
else padrePrecedente.children.push(nuovoPadre);
};
}
else result.children.push(father);
});
});
This is currently my working code.. I'm struggling tryng to understand your code #chriss
Try this one:
function getGroupedByName(given) {
let result = given.reduce((a, b) => {
if(!a[b.name]) a[b.name] = [];
a[b.name] = [...a[b.name], ...b.children];
return a;
}, {});
result = Object.keys(result).map(key => ({name: key, children: getByName(result[key])}));
return result;
}
const o = []; // your initial object
getGroupedByName(o, "Leggi")
It is returning it as an array of objects having name and children props, as i am assuming first level can also have multiple different names, not all being ""
It goes first trough all elements in array and groups them into object with structure { name: children } where children is array of all children for same group.
For each children array it preforms same operation, going trough array and flattening it into { name: children } object.
At this moment we have following structure:
{ "": {
Leggi: {...}
}}
When everything is grouped, Object.keys loops trough all keys and breaks it into array where key is name and value children property
I'm trying to change the structure of a json by removing duplicate keys. Otherwise, to put the children of a same name inside only one name node.
Current JSON:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{
"name": "AgglomerativeCluster",
"size": [
"3938"
]
}
]
}
]
},
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{
"name": "CommunityStructure",
"size": [
"3812"
]
}
]
}
]
}
]
}
Desired output:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{
"name": "AgglomerativeCluster",
"size": 3938
},
{
"name": "CommunityStructure",
"size": 3812
}
]
}
]
}
]
};
Thanks for your help.
Typically, StackOverflow isn't the place to have people write code for you, and your question should be more specific as to with what part of your algorithm you are having trouble. However, this looked fun, so I did it.
I solved this by first converting it to an object whose properties are the names and values are the children/size. This insured that each named instance was grouped with other named instances.
var mutate = function(desired, current) {
for (var x = 0; x < current.length; x++) {
if (Object.hasOwnProperty.call(current[x], 'size')) {
desired[current[x].name] = parseInt(current[x].size[0], 10);
}
else {
if (!Object.hasOwnProperty.call(desired, current[x].name)) {
desired[current[x].name] = Object.create(null);
}
mutate(desired[current[x].name], current[x].children);
}
}
return desired;
};
I then converted that back to your original desired format by iterating over the Object.entries (key/value pairs).
var mutate2 = function(current) {
var desired = [];
var entries = Object.entries(current);
for (var x = 0; x < entries.length; x++) {
var o = Object.create(null);
o.name = entries[x][0];
if (typeof entries[x][1] === 'number') {
o.size = entries[x][1];
}
else {
o.children = mutate2(entries[x][1]);
}
desired.push(o);
}
return desired;
};
You get your result by using this hideous beast:
var desiredJson = mutate2(mutate(Object.create(null), [ currentJson ]));
console.log(desiredJson);
I have an array of objects. I would like to reformat into a new array but am not sure how to begin. I have jQuery and Underscore available.
Here is my original array:
var myArray = [
{
"name": "Product",
"value": "Car"
},
{
"name": "Product",
"value": "Boat"
},
{
"name": "Product",
"value": "Truck"
},
{
"name": "Color",
"value": "Blue"
},
{
"name": "Location",
"value": "Store"
}
];
Here is what I am trying to make the new Array look like:
var newArray = [
{
"name": "Product",
"value": "Car Boat Truck"
},
{
"name": "Color",
"value": "Blue"
},
{
"name": "Location",
"value": "Store"
}
];
In the newArray the Products are all in one object.
You can use the groupBy method to get all the elements with the same name together, then map to transform them into what you want. And pluck is useful here to combine the values in the output array.
Here's quick, simple solution:
var newArray = _.chain(myArray)
.groupBy("name")
.map(function(a) {
return {
"name": a[0].name,
"value": _.pluck(a, "value").join(" ")
};
})
.value();
Demonstration
And just for completeness, here's the non-chained version:
var newArray = _.map(_.groupBy(myArray, "name"), function(a) {
return {
"name": a[0].name,
"value": _.pluck(a, "value").join(" ")
};
});
Here's a more generalized solution that's reusable and not hard-coded. This way, you can create multiple groupBy methods for different properties of different object collections, then join the properties that you require. jsFiddle
function groupBy(groupBy) {
return function(source, joinOn) {
return _.each(_.groupBy(source, groupBy), function(val, key, context){
context[key] = _.pluck(val, joinOn).join(' ');
});
};
}
var groupByNameOn = groupBy('name');
console.log(groupByNameOn(arr, 'value'));