Convert nested Json to flat Json with parentId to every node - javascript

The following Json structure is a result of Neo4J apoc query. I want to convert this nested Json to flat Json structure as shown in the second json.
[
{
"child1": [
{
"_type": "EntityChild1",
"name": "Test222",
"_id": 2
}
],
"child2": [
{
"_type": "EntityChild2",
"name": "Test333",
"_id": 3,
"child2_child1": [
{
"_type": "EntityChild2_1",
"name": "Test444",
"_id": 6,
"child2_child1_child1": [
{
"_type": "EntityChild2_1_1",
"name": "Test555",
"_id": 7
}
]
}
]
}
],
"_type": "EntityParent",
"name": "Test000",
"_id": 1,
"child3": [
{
"_type": "EntityChild3",
"name": "Test111",
"_id": 4
}
],
"child4": [
{
"_type": "EntityChild4",
"name": "Test666",
"_id": 5
}
]
}
]
This is the result i am looking for, I also want the parentId appended to every node. If no parent is there for a particular node then it should have parentid as -1.
[
{
"_type": "EntityParent",
"name": "Test000",
"_id": 1,
"parentid": -1
},
{
"_type": "EntityChild1",
"name": "Test222",
"_id": 2,
"parentid": 1
},
{
"_type": "EntityChild2",
"name": "Test333",
"_id": 3,
"parentid": 1
},
{
"_type": "EntityChild2_1",
"name": "Test444",
"_id": 6,
"parentid": 3
},
{
"_type": "EntityChild2_1_1",
"name": "Test555",
"_id": 7,
"parentid": 6
},
{
"_type": "EntityChild3",
"name": "Test111 ",
"_id": 4,
"parentid": 1
},
{
"_type": "EntityChild4",
"name": "Test666",
"_id": 5,
"parentid": 1
}
]
Let me know if any further information is required.

You could take an iterative and recursive approach by using a function which takes an array and a parent id for the actual level.
If a property starts with child, it calls the function again with the actual _id and pushes all items to the result set.
function getFlat(array, parentid) {
return array.reduce((r, o) => {
var temp = {};
r.push(temp);
Object.entries(o).forEach(([k, v]) => {
if (k.startsWith('child')) {
r.push(...getFlat(v, o._id));
} else {
temp[k] = v;
}
});
temp.parentid = parentid;
return r;
}, []);
}
var data = [{ child1: [{ _type: "EntityChild1", name: "Test222", _id: 2 }], child2: [{ _type: "EntityChild2", name: "Test333", _id: 3, child2_child1: [{ _type: "EntityChild2_1", name: "Test444", _id: 6, child2_child1_child1: [{ _type: "EntityChild2_1_1", name: "Test555", _id: 7 }] }] }], _type: "EntityParent", name: "Test000", _id: 1, child3: [{ _type: "EntityChild3", name: "Test111", _id: 4 }], child4: [{ _type: "EntityChild4", name: "Test666", _id: 5 }] }],
flat = getFlat(data, -1);
console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

neo4j query to get a specific formated response

I am having a node network in the neo4j database which includes multilevel nodes something like,
parent -> child -> sub child -> ...and so on
Now what I need is I need to write a query that will give me the response in the below format.
nodes = [
{
id: parent1,
children : [{
id: child1,
children: [
{
id: sub child1,
children: [... So on]
},
{
id: sub child2,
children: [... So on]
}
]
}]
},
{
id = parent2,
children : [...so on]
}
]
You can do something like:
MATCH (p:Person)
WHERE size((p)<--()) = 0
CALL apoc.path.expandConfig(p, {
relationshipFilter: "PARENT>"
})
YIELD path
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
Matching the top parents, which points no one, then using apoc.path.expandConfig to get their paths and then apoc.convert.toTree in order to get the tree-shape structure that you want.
On a sample data:
MERGE (a:Person{key: 1})
MERGE (b:Person{key: 2})
MERGE (c:Person{key: 3})
MERGE (d:Person{key: 4})
MERGE (e:Person{key: 5})
MERGE (f:Person{key: 6})
MERGE (g:Person{key: 7})
MERGE (h:Person{key: 8})
MERGE (i:Person{key: 9})
MERGE (b)-[:PARENT]-(a)
MERGE (d)-[:PARENT]-(c)
MERGE (d)-[:PARENT]-(i)
MERGE (f)-[:PARENT]-(e)
MERGE (g)-[:PARENT]-(b)
MERGE (g)-[:PARENT]-(d)
MERGE (e)-[:PARENT]-(h)
It returns:
[{
"_type": "Person",
"parent": [
{
"_type": "Person",
"parent": [
{
"_type": "Person",
"_id": 1444,
"key": 8
}
],
"_id": 1441,
"key": 5
}
],
"_id": 1442,
"key": 6
},
{
"_type": "Person",
"parent": [
{
"_type": "Person",
"parent": [
{
"_type": "Person",
"_id": 1437,
"key": 1
}
],
"_id": 1438,
"key": 2
},
{
"_type": "Person",
"parent": [
{
"_type": "Person",
"_id": 1439,
"key": 3
},
{
"_type": "Person",
"_id": 1445,
"key": 9
}
],
"_id": 1440,
"key": 4
}
],
"_id": 1443,
"key": 7
}]

Sort array of objects by the length of a field using lodash [duplicate]

This question already has answers here:
How to sort an array based on the length of each element?
(12 answers)
Closed 1 year ago.
I have an array like below, and I need to sort the array by the string length of name field.
for an example,
[
{
"_id": 10,
"name": "AAAAAA"
},
{
"_id": 11,
"name": "AA"
},
{
"_id": 12,
"name": "AAAA"
},
{
"_id": 13,
"name": "A"
},
{
"_id": 14,
"name": "AAAAAAAA"
}
]
I need the array like this,
[
{
"_id": 13,
"name": "A"
},
{
"_id": 11,
"name": "AA"
},
{
"_id": 12,
"name": "AAAA"
},
{
"_id": 10,
"name": "AAAAAA"
},
{
"_id": 14,
"name": "AAAAAAAA"
}
]
can any one help me out with this. Thanks.
This can be accomplished with the _.orderBy method:
_.orderBy(data, [({ name }) => name.length, 'name'], ['desc']);
Here is a break-down:
I threw some "B"s into the mix to show the secondary sorting (after length is compared). Sorting the length alone is not unique enough.
const data = [
{ "_id": 1, "name": "AAAAAA" },
{ "_id": 2, "name": "AA" },
{ "_id": 3, "name": "AAAA" },
{ "_id": 4, "name": "A" },
{ "_id": 5, "name": "AAAAAAAA" },
{ "_id": 6, "name": "BBBBBB" },
{ "_id": 7, "name": "BB" },
{ "_id": 8, "name": "BBBB" },
{ "_id": 9, "name": "B" },
{ "_id": 10, "name": "BBBBBBBB" }
];
const sorted = _.orderBy(
data, // Data to be sorted
[
({ name: { length } }) => length, // First, sort by length
'name' // Them sort lexicographically
], [
'desc', // Length (descending)
'asc' // This is implied, and could be removed
]
);
console.log(sorted);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

How do I loop through nested arrays?

I have this structure below, and I want to loop through the hierarchy without missing any object.
{
"countries": [
{
"name": "Denmark",
"id": "APA1",
"children": [
{
"name": "Zealand",
"id": "APA1.1",
"parentId": "APA1",
"children": [
{
"name": "Copenhagen",
"id": "APA1.1.1",
"parentId": "APA1.1",
"children": [
{
"name": "Dublin",
"id": "ANA1",
"parentId": "APA1.1.1.1",
"hostNames": [
{
"ip": "20.190.129.1"
},
{
"ip": "20.190.129.2"
}
]
}
]
}
]
},
{
"name": "Jutland",
"id": "APA1.2",
"parentId": "APA1",
"children": [
{
"name": "Nordjylland",
"id": "APA1.2.1",
"parentId": "APA1.2",
"children": [
{
"name": "Aalborg",
"id": "APA1.2.1.1",
"parentId": "APA1.2.1",
"children": [
{
"name": "Risskov",
"id": "ANA3",
"parentId": "APA1.2.1.1",
"hostNames": [
{
"ip": "40.101.81.146"
}
]
},
{
"name": "Brabrand",
"id": "ANA4",
"parentId": "APA1.2.1.1",
"hostNames": [
{
"ip": "43.203.94.182"
}
]
}
]
}
]
}
]
}
]
}
]
}
The reason why I want to loop through the hierarchy is that I want to turn this into a flat structure. So essentially I'm gonna take every object and move it to another array which has the structure that I want. I just want to know how to access the children.
The wanted result:
"applicationGroups": [
{
"id" : "APA1",
"name": "Denmark",
},
{
"name": "Zealand",
"id": "APA1.1",
"parentId": "APA1"
},
{
"name": "Copenhagen",
"id": "APA1.1.1",
"parentId": "APA1.1"
},
{
"name": "Dublin",
"id": "ANA1",
"parentId": "APA1.1.1.1"
},
{
"name": "Jutland",
"id": "APA1.2",
"parentId": "APA1"
},
{
"name": "Nordjylland",
"id": "APA1.2.1",
"parentId": "APA1.2"
},
{
"name": "Aalborg",
"id": "APA1.2.1.1",
"parentId": "APA1.2.1"
},
{
"name": "Risskov",
"id": "ANA3",
"parentId": "APA1.2.1.1"
},
{
"name": "Brabrand",
"id": "ANA4",
"parentId": "APA1.2.1.1"
}
]
I'm a bit new to JavaScript, and I don't really know where to start, but this example that I have given is not identical to the actual one that I'm working on, so I just want the principle so I can implement it myself in my actual code.
You could take a flatMap approach for the recursive call of a flattening callback.
const
flat = ({ hostNames, children = [], ...o }) => [o, ...children.flatMap(flat)],
data = { countries: [{ name: "Denmark", id: "APA1", children: [{ name: "Zealand", id: "APA1.1", parentId: "APA1", children: [{ name: "Copenhagen", id: "APA1.1.1", parentId: "APA1.1", children: [{ name: "Dublin", id: "ANA1", parentId: "APA1.1.1.1", hostNames: [{ ip: "20.190.129.1" }, { ip: "20.190.129.2" }] }] }] }, { name: "Jutland", id: "APA1.2", parentId: "APA1", children: [{ name: "Nordjylland", id: "APA1.2.1", parentId: "APA1.2", children: [{ name: "Aalborg", id: "APA1.2.1.1", parentId: "APA1.2.1", children: [{ name: "Risskov", id: "ANA3", parentId: "APA1.2.1.1", hostNames: [{ ip: "40.101.81.146" }] }, { name: "Brabrand", id: "ANA4", parentId: "APA1.2.1.1", hostNames: [{ ip: "43.203.94.182" }] }] }] }] }] }] },
result = data.countries.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can combine the Array.flat() method and this answer to flatten objects recursively.
Using recursive functions is the faster way to accomplish that.
To get a flat structure you could use reduce method to create recursive function.
const data = {"countries":[{"name":"Denmark","id":"APA1","children":[{"name":"Zealand","id":"APA1.1","parentId":"APA1","children":[{"name":"Copenhagen","id":"APA1.1.1","parentId":"APA1.1","children":[{"name":"Dublin","id":"ANA1","parentId":"APA1.1.1.1","hostNames":[{"ip":"20.190.129.1"},{"ip":"20.190.129.2"}]}]}]},{"name":"Jutland","id":"APA1.2","parentId":"APA1","children":[{"name":"Nordjylland","id":"APA1.2.1","parentId":"APA1.2","children":[{"name":"Aalborg","id":"APA1.2.1.1","parentId":"APA1.2.1","children":[{"name":"Risskov","id":"ANA3","parentId":"APA1.2.1.1","hostNames":[{"ip":"40.101.81.146"}]},{"name":"Brabrand","id":"ANA4","parentId":"APA1.2.1.1","hostNames":[{"ip":"43.203.94.182"}]}]}]}]}]}]}
function flat(data) {
return data.reduce((r, { children, ...rest }) => {
if (children) r.push(...flat(children))
r.push(rest)
return r;
}, [])
}
const result = flat(data.countries)
console.log(result)

Extract objects from nested array of objects

I have the following data that is an array of nested objects:
"categories": [
{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
]
I want to extract unique years in a separate array (desired output):
[
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" },
]
When I map out the years, I'm getting an array of arrays, how should I extract the unique objects for years?
let years = categories.map( (c) => { return c.years })
You can use a Map to filter duplicate years from the array of values using id as the key, and reduce() on both categories and years using the map as the accumulator:
const categories = [{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
];
const years = categories.reduce(
(map, category) => category.years.reduce(
(map, year) => map.set(year.id, year),
map
),
new Map()
);
console.log([...years.values()]);
You can use reduce and Map
let data = [{"id": 1,"name": "Category 1","years": [{ "id": 1, "name": "1" },{ "id": 2, "name": "2" }]},{"id": 2,"name": "Category 2","years": [{ "id": 2, "name": "2" },{ "id": 3, "name": "3" }]}]
let final = data.reduce((op,{years}) => {
years.forEach(({id, name}) => {
let key = id + '-' + name
op.set(key, op.get(key) || {id, name})
})
return op
},new Map())
console.log([...final.values()])

flattening nested json object

[
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
]
This is a representation of Chrome bookmarks data.
If the object has url property it means that is a bookmark. If it does not have url property it is a folder.
It is a tree structure.
I would like to create flatten object with additional property named type. Like:
[
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "title",
"url": "some url",
"type": "bookmark"
},
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1402",
"title": "title2",
"url": "some url2"
"type": "folder"
}
]
Thanks in advance.
You could use an iterative and recursive approach for getting flat data.
function flatten(array) {
var result = [];
array.forEach(function iter(o) {
var temp = {},
keys = Object.keys(o);
if (keys.length > 1) {
keys.forEach(function (k) {
if (k !== 'children') {
temp[k] = o[k];
}
});
temp.type = 'url' in o ? 'bookmark' : 'folder';
result.push(temp);
}
Array.isArray(o.children) && o.children.forEach(iter);
});
return result;
}
var data = [{ children: [{ children: [{ dateAdded: 1493033302670, id: "1534", index: 0, parentId: "1", title: "data1", url: "data2" }, { children: [{ dateAdded: 1489571506844, id: "1451", index: 0, parentId: "1401", title: "data3", url: "data4" }], dateAdded: 1490363326576, dateGroupModified: 1490363326576, id: "1401", index: 1, parentId: "1", title: "daily" }, { children: [{ dateAdded: 1481787664555, id: "1429", index: 0, parentId: "1407", title: "data56", url: "data" }, { dateAdded: 1483365608504, id: "1430", index: 1, parentId: "1407", title: "data34", url: "data55" }] }] }] }];
console.log(flatten(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I've made a function that iterates through an array containing objects. If a given object has a property called children, the function calls itself. If it doesn't, then it gets pushed to a new array flattenedBookmarks.
The Solution
var flattenedBookmarks = [];
flattenBookmarks(bookmarks);
function flattenBookmarks(bookmarks) {
for (var i = 0; i < bookmarks.length; i++) {
var potentialBookmark = bookmarks[i];
if (potentialBookmark.hasOwnProperty("url")) {
potentialBookmark.type = "bookmark";
} else {
potentialBookmark.type = "folder";
}
if (potentialBookmark.hasOwnProperty("children")) {
flattenBookmarks(potentialBookmark.children);
if (potentialBookmark.hasOwnProperty("dateGroupModified")) {
flattenedBookmarks.push(potentialBookmark);
}
} else {
flattenedBookmarks.push(potentialBookmark);
}
}
}
You should probably be returning the flattened array from the function instead of storing it in a new global array flattenedBookmarks, but at least this will get you started.
https://jsfiddle.net/s9ur35re/
The example shows how to do it
data = [
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
];
data2 = [];
function search(data) {
for (n in data) {
if (typeof data[n] == 'object') {
if (data[n].id != undefined) {
if (data[n].url != undefined) {
data[n].type="folder";
} else {
data[n].type="bookmark";
}
data2.push(data[n]);
}
search(data[n]);
}
}
}
search(data);
console.log(data2);

Categories

Resources