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
}]
Related
I have a data array, there are multiple objects in this array, and the data object is an array. There may be more than one object in this array. How can I copy these objects under a single array?
const test = []
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
]
[{
"price":10,
"title": "sda"
},
{
"price":20,
"title": "asdas"
},
]
If this is the output I expect, it should be like this. how can I do that
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
{
"price":99,
"title":"aaaaa"
}
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
];
console.log(data.map(e => e.data).flat());
// OR
console.log(data.flatMap(e => e.data));
I am trying to alter the json in snippet to a tree structure just like in https://www.primefaces.org/primeng/#/treetable (below is the sample i expect too). I understand it involves recursion but I ain't sure how to deeply link each.
The output i expect is something like below. The json whose parent is true becomes the root. If the root has values, the json corresponding to id of the value is pushed to children array with a json object "data". Again if that json has values, the json correspond to the id of value is pushed to children array with a json object "data and so on.
The code i have written is just a initial phase. Need help on how nesting can be done through iteration.
[
{
"data": {
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P001",
"type": "File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
"children": [
{
"data": {
"parent": false,
"id": "P002",
"type": "Image",
"values": [
]
}
}
]
}
]
},
{
"data": {
"parent": true,
"id": "S000",
"type": "Something",
"values": [
]
}
}
]
var junkdata=[
{
"parent": false,
"id": "P001",
"type":"File",
"values": [
{
"id": "P002",
"type": "Image"
}
]
},
{
"parent": true,
"id": "C001",
"type": "Folder",
"values": [
{
"id": "P001",
"type": "File"
}]
},
{
"parent": false,
"id": "P002",
"type": "Image",
"values":[]
},
{
"parent": true,
"id": "S000",
"type": "Something",
"values":[]
}];
var parentDatas=junkdata.filter((x)=>x.parent==true);
if(parentDatas.length>0){
var finalResponse=parentDatas.map((parentData)=>{
var resultJson={};
resultJson.data=parentData;
if(parentData.values.length>0){
resultJson.children=[];
for(var i of parentData.values){
var child=junkdata.find((x)=>x.id==i.id);
if(child){
var jsonObj={};
jsonObj.data=child;
resultJson.children.push(jsonObj);
}
}
}
return resultJson;
})
}
console.log(JSON.stringify(finalResponse));
Basically, we can start with this to process the root nodes:
let tree = yourData.filter(x => x.parent).map(process);
where process is the recursive function that processes a given node:
let process = node => ({
id: node.id,
type: node.type,
children: node.values.map(x => process(
yourData.find(y => y.id === x.id)))
});
For each id in node.values, it locates a node with that id and recursively calls process on it. Once all child nodes are dealt with, process collects them into an array and returns the newly formatted object.
This is the general recursion pattern for working with graph-alike structures, where you have "nodes" somehow connected to other "nodes":
function F (N: node) {
for each node M which is connected to N {
F (M) <--- recursion
}
result = do something with N
return result
}
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; }
As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>
I have a json data in this format and I would like to load data in an array which is an object, without hard coding the object keys. I would like to get items and labels in each category and each category has it name for object key. At the moment I get the data by
...myData.labels.name; or ...items.name; which is not effective because
the name changes depending on the category.
[
[
{
"key": "mykey",
"category": "myCategoryKey",
"category_label": "myCategoryLabel",
"field": "filter",
"items": {
"name": [
"item1",
"item2"
]
},
"labels": {
"name": [
"Item1",
"Item2"
]
}
},
{
"key": "mykey2",
"category": "myCategoryKey2",
"category_label": "myCategoryLabel2",
"field": "filter",
"items": {
"name2": [
"item1",
"item2"
]
},
"labels": {
"name3": [
"Item1",
"Item2"
]
}
}
]
]
Use Object.keys() to get Keys for items present if values change dynamically.
And then use the keys to get corresponding values.
var data = {
"key": "mykey2",
"category": "myCategoryKey2",
"category_label": "myCategoryLabel2",
"field": "filter",
"items": {
"name2": [
"item1",
"item2"
]
},
"labels": {
"name3": [
"Item1",
"Item2"
]
} }
var labelsPresent = Object.keys(data.labels);
console.log(labelsPresent);
var labelValues= labelsPresent[0];
console.log(data.labels[labelValues]);