Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
01-06-2022 05:51 AM
I have a tree structure like a folder structure so with a project with nested project without a depth limit, each node has access rights on them.
Here is my graph:
Here is my query:
MATCH (a:Account {name: "bob"})-[r:VIEWER | EDITOR]->(c:Project)
MATCH (c)<-[:IS_PARENT*]-(p)
WHERE (p)<-[:VIEWER | EDITOR]-(a)
WITH TYPE(r) as relation, p, collect(distinct c) AS children
RETURN {name: p.name, Children: [c in children | {name: c.name, access:relation}]}
Here is my result:
{
"name": "project test",
"Children": [
{
"access": "VIEWER",
"name": "cohort"
},
{
"access": "VIEWER",
"name": "experience"
}
]
}
{
"name": "project test",
"Children": [
{
"access": "EDITOR",
"name": "protocol"
},
{
"access": "EDITOR",
"name": "nested child"
}
]
}
{
"name": "cohort",
"Children": [
{
"access": "EDITOR",
"name": "nested child"
}
]
}
And this is what I want to get:
{
name: "Project 1",
access: "VIEWER",
children: [
{
name: "cohort",
access: "VIEWER",
children: [
{
name: "nested",
access: "EDITOR",
},
]
},
{
name: "protocol",
access: "EDITOR",
},
{
name: "expererience",
access: "VIEWER",
}
]
}
My problem is that the result is split in two results, and nested child
isn't nested in cohort
.
An other thing that is tricky is that I don't want to get a node if I don't have a relation with it.
For example here I removed the relation between bob
and cohort
:
So I must not get cohort
in my result, like this:
{
name: "Project 1",
access: "VIEWER",
children: [
{
name: "nested child",
access: "EDITOR",
},
{
name: "protocol",
access: "EDITOR",
},
{
name: "expererience",
access: "VIEWER",
}
]
}
Here is my data if you want to try:
MERGE (project:Project:RootProject {name: "project test"})
MERGE (child1:Project {name: "cohort"})
MERGE (child2:Project {name: "protocol"})
MERGE (child3:Project {name: "experience"})
MERGE (child4:Project {name: "nested child"})
MERGE (project)-[:IS_PARENT]->(child1)
MERGE (project)-[:IS_PARENT]->(child2)
MERGE (project)-[:IS_PARENT]->(child3)
MERGE (child1)-[:IS_PARENT]->(child4)
MERGE (bob:Account {name: "bob"})
MERGE (bob)-[:EDITOR]->(child4)
MERGE (bob)-[:EDITOR]->(child2)
MERGE (bob)-[:VIEWER]->(child3)
MERGE (bob)-[:VIEWER]->(child1)
MERGE (bob)-[:VIEWER]->(project)
I have tried a lot of things but I never get a good result.
01-07-2022 12:15 AM
Hi,
To begin with you could try this procedure:
And there is an example here:
I will test if I can fix the filtering as soon as I have time.
01-07-2022 01:34 AM
To accomplish this I've to create a temporarily CHILD relation.
Didn't find any apoc that can create a virtual paths from nodes. Which would be a better solution.
To rerun the solution you have to delete the child relations at the beginning ohterwise there will be doubles.
Firstly find all longest paths, and remove all nodes in the paths that don't have an outlink of IS_PARENT.
Then create child relations between them.
MATCH path=(a:Account {name: "bob"})-[:VIEWER | EDITOR]->(c:Project)-[:IS_PARENT *]->(dest:Project)
WHERE not exists((dest)-[:IS_PARENT]->())
with [n in nodes(path) where (n)<-[:VIEWER | EDITOR]-()|n] as nodes
call apoc.nodes.link(nodes,'CHILD')
Then you can run the following to get result that is near what you want.
MATCH path=(s)-[:CHILD *]->(d)
with collect(path) as paths
call apoc.convert.toTree(paths) yield value
return value
Clean up the CHILD relations
match ()-[C:CHILD]->() DELETE C
01-10-2022 07:40 AM
@filantrop
Hi thanks you for your answer it helps a lot, It is nearly exactly what i want.
I have 3 questions:
(cohort) -> (nested child) -> (new child)
What i get :
{
"_type": "Project:RootProject",
"name": "project test",
"_id": 12,
"child": [
{
"_type": "Project",
"name": "cohort",
"_id": 14,
"child": [
{
"_type": "Project",
"name": "nested child",
"_id": 20,
"child": [
{
"_type": "Project",
"name": "sous projet",
"_id": 34
}
]
}
]
},
{
"_type": "Project",
"name": "protocol",
"_id": 16
},
{
"_type": "Project",
"name": "experience",
"_id": 18
}
]
}
//------------------Result 2-------------------------
{
"_type": "Project",
"name": "cohort",
"_id": 14,
"child": [
{
"_type": "Project",
"name": "nested child",
"_id": 20,
"child": [
{
"_type": "Project",
"name": "sous projet",
"_id": 34
}
]
}
]
}
//-----------------Result 3--------------------------
{
"_type": "Project",
"name": "nested child",
"_id": 20,
"child": [
{
"_type": "Project",
"name": "sous projet",
"_id": 34
}
]
}
My second question is:
Is there a way to add the type of relation bob
has with each child
in the same query ?
"Children": [
{
"access": "EDITOR",
"name": "protocol"
},
{
"access": "EDITOR",
"name": "nested child"
}
]
And my last question:
If i remove the relation between bob
and the RootProject
, the query doesn't return a correct result, how can we fix this ?
01-08-2022 08:11 AM
I wasn't able to get exactly what you want. Your structure will require an iterative algorithm to get the child nesting you want. I was able to get the following output, which gives you the child nodes along each path. If you are going to process this output in a program, such as java, you could parse it and rearrange the paths into nested children. How this helps a little. I didn't bother trying to simply the query, since it is not what you wanted.
Query:
MATCH (a:Account {name: "bob"})-[r:VIEWER | EDITOR]->(c:Project)
MATCH path=(rootNode)-[:IS_PARENT*]->(c)
MATCH (rootNode)<-[q:VIEWER | EDITOR]-(a)
WHERE NOT exists(()-[:IS_PARENT]->(rootNode))
WITH rootNode, type(q) as rootType, type(r) as nodeType, path
CALL {
WITH path, nodeType
UNWIND tail(nodes(path)) as node
WITH {access:nodeType, name:node.name} as grouped
return collect(grouped) as groupedNodesOnPath
}
WITH rootNode, rootType, collect(groupedNodesOnPath) as children
RETURN rootNode{.name, access:rootType, children:children}
Output:
{
"access": "VIEWER",
"children": [
[
{
"access": "VIEWER",
"name": "cohort"
}
],
[
{
"access": "VIEWER",
"name": "experience"
}
],
[
{
"access": "EDITOR",
"name": "protocol"
}
],
[
{
"access": "EDITOR",
"name": "cohort"
},
{
"access": "EDITOR",
"name": "nested child"
}
]
],
"name": "project test"
}
01-10-2022 02:27 PM
Question 1: If I am understanding your statement, you are getting multiple paths from your query, which you don't want. These are resulting from each of the following match clause;
MATCH path=(rootNode)-[:IS_PARENT*]->(c)
This results in a path for each of the nodes that has an outgoing 'IS_PARENT' relationship. I assumed in my query that you did not want that, but wanted the path from the root of the graph. I accomplished that by added the following where clause:
WHERE NOT exists(()-[:IS_PARENT]->(rootNode))
This eliminates those nodes that have an incoming 'IS_PARENT' relationship, which indicate that are not at the root of the graph. This should eliminate the multiple paths, and return just one result starting from the root of the graph. In your case, that is the 'project test' node.
Question 2. Isn't that what the 'access' attribute is for each child? If I misunderstand, clarify and I will try to help.
All the sessions of the conference are now available online