In this Neo4j query, I want to return only relation and that only specific relation called "Permission". So how can I filter it and get the expected answer?
MATCH (end:Directory) WHERE end.name = "dir1.5"
WITH shortestPath((start)-[*]->(end)) AS p
RETURN p
ORDER BY length(p)
Once you have a path, you can filter on specific types of relationships doing this
WITH [r IN relationships(path) WHERE r.type = 'Permission'] AS rs
UNWIND rs AS r
RETURN r
If you want to visualize the r in the Neo4j broser, you may need to add the start and endnodes, so it becomes
RETURN startNode(r),r,endNode(r)
Related
I'm trying to make a cypher query to make nodes list which is using "multi match" as follows:
MATCH (N1:Node)-[r1:write]->(P1:Node),
(P1:Node)-[r2:access]->(P2:Node)<-[r3:create]-(P1)
WHERE r1.Time <r3.Time and r1.ID = r2.ID and r3.Time < r2.Time
return nodes(*)
I expect the output of the Cypher to be all nodes of the result, but Cypher doesn't support nodes(*).
I know that there is a way to resolve this like thisa;
MATCH G1=(N1:Node)-[r1:write]->(P1:Node),
G2=(P1:Node)-[r2:access]->(P2:Node)<-[r3:create]-(P1)
WHERE r1.Time <r3.Time and r1.ID = r2.ID and r3.Time < r2.Time
return nodes(G1), nodes(G2)
But the match part could be changed frequently so I want to know the way to get nodes from multi-match without handling variable for every match.
Is it possible?
Your specific example is easy to consolidate into a single path, as in:
MATCH p=(:Node)-[r1:write]->(p1:Node)-[r2:access]->(:Node)<-[r3:create]-(p1)
WHERE r1.Time < r3.Time < r2.Time AND r1.ID = r2.ID
RETURN NODES(p)
If you want the get distinct nodes, you can replace RETURN NODES(p) with UNWIND NODES(p) AS n RETURN DISTINCT n.
But, in general, you might be able to use the UNION clause to join the results of multiple disjoint statements, as in:
MATCH p=(:Node)-[r1:write]->(p1:Node)-[r2:access]->(:Node)<-[r3:create]-(p1)
WHERE r1.Time < r3.Time < r2.Time AND r1.ID = r2.ID
UNWIND NODES(p) AS n
RETURN n
UNION
MATCH p=(q0:Node)-[s1:create]->(q1:Node)-[s2:read]->(q0)
WHERE s2.Time > s1.Time AND s1.ID = s2.ID
UNWIND NODES(p) AS n
RETURN n
The UNION clause would combine the 2 results (after removing duplicates). UNION ALL can be used instead to keep all the duplicate results. The drawback of using UNION (ALL) is that variables cannot be shared between the sub-statements.
How can I know how many nodes and edges are involved in a MATCH? Is there another way besides Explain / Profile Match?
If you mean how many nodes are matched in a path, such as a variable-length path, then you can assign a path variable for this:
MATCH p = (k:Person {name:'Keanu Reeves'})-[*..8]-(t:Person {name:'Tom Hanks'})
WITH p LIMIT 1
RETURN p, length(p) as pathLength, length(p) + 1 as numberOfNodesInPath
You can also use nodes(p) and relationships(p) to get the collection of nodes and relationships that make up the path, and you can use size() on those collections to get their size.
There exists the COUNT() function of Cypher that allows you to count the number of elements. As for example in this query:
MATCH (n)
RETURN COUNT(n);
This query will count all nodes in your database.
You can find more information in the cypher manual, under the aggregating functions. Check it out.
The following Cypher snippet should return the number of distinct nodes and relationships found by any given MATCH clause. Just replace <your code here> with your MATCH pattern.
MATCH <your code here>
WITH COLLECT(NODES(p)) AS ns, SUM(SIZE(RELATIONSHIPS(p))) AS relCount
UNWIND ns AS nodeList
UNWIND nodeList AS node
RETURN COUNT(DISTINCT node) AS nodeCount, relCount;
I have the following graph:
I need to get all the AD nodes which are related to a particular User node. If I search by a user B1, I should get all the AD nodes which are connected by HAS relation to B1 node as well as the AD nodes which are connected to its parent by HAS relation. But if any of these AD nodes are connected by an EXCLUDES relation, I should filter that one out.
For example, if I search by B1, I should get AD4,AD2
AD1 has EXCLUDES with D1 and AD3 has excludes with C1, hence filtered out.
I am using the following cypher
MATCH path=(p:AD)-[:HAS|EXCLUDES]-()<-[:CHILD_OF*]-(u:User) USING INDEX u:User(id) WHERE u.id = 'B1'
with p,
collect( filter( r in rels(path)
where type(r) = 'EXCLUDES'
)
) as test
where all( t in test where size(t) = 0 )
return p
The issue is when I search with C1, it return AD4,AD3,AD2. How can I eliminate AD3 from the result?
:CHILD_OF* doesn't include your starting node. To include that, set a lowerbound of 0:
[:CHILD_OF*0..]
That said, there are probably better ways to form your query. Try this, maybe:
MATCH (u:User)
WHERE u.id = 'B1'
WITH u, [(p:AD)-[:EXCLUDES]-()<-[:CHILD_OF*0..]-(u) | p] as excluded
MATCH (p:AD)-[:HAS]-()<-[:CHILD_OF*0..]-(u)
WHERE not p in excluded
RETURN p
EDIT
The pattern comprehension feature was released with Neo4j 3.1. You won't be able to use that in an older version. Try this instead:
MATCH (u:User)
WHERE u.id = 'B1'
OPTIONAL MATCH (p:AD)-[:EXCLUDES]-()<-[:CHILD_OF*0..]-(u)
WITH u, collect(p) as excluded
MATCH (p:AD)-[:HAS]-()<-[:CHILD_OF*0..]-(u)
WHERE not p in excluded
RETURN p
Given following database schema:
I would like to return the movie that connects the actor Bruce Wilis to the director Oliver Stone using the shortestPath() function.
My attempt:
match p = shortestPath((d:Director{director_name:'Oliver Stone'})-[*]- (a:Actor{actor_name:'Bruce Willis'}))
with nodes(p) as n
where type(n) = 'Movie'
return n
The problem in your attempted query is that nodes(p) is a collection of nodes. Trying to use type() on a collection of nodes won't work. Also, type() is only used to get the type of a relationship. Nodes don't have types, they have labels.
Also, you don't know if there is just a single movie node, or multiple movie nodes, in the shortest path between your starting nodes, so the best approach is to filter the collection so you only keep movie nodes in the path:
match p = shortestPath((d:Director{director_name:'Oliver Stone'})-[*]- (a:Actor{actor_name:'Bruce Willis'}))
return [n in nodes(p) where n:Movie] as movies
This uses list comprehension to perform the filtering of the collection. Alternately, you can use the filter() function:
return filter(n in nodes(p) where n:Movie) as movies
I opened this question here: How to find specific subgraph in Neo4j using where clause to find a path of a certain criteria. Yet when I try to do things like get the relationship type I cannot.
For example I tried MATCH p = (n:Root)-[rs1*]->()
WHERE ALL(rel in rs1 WHERE rel.relevance is null)
RETURN nodes(p), TYPE(relationships(p))
But I get the error:
Type mismatch: expected Relationship but was Collection<Relationship>
I think I need to use a WITH clause but not sure.
Similarly I wanted the ID of a node but that also failed.
The problem is that relationships returns a collection and the type function only works on a single relationship. There are two main approaches to solve this.
Use UNWIND to get a separate row for each relationship:
MATCH p = (n:Root)-[rs1*]->()
WHERE ALL(rel in rs1 WHERE rel.relevance is null)
WITH relationships(p) AS rs
UNWIND n, rs AS r
RETURN n, type(r)
Use extract to get the results in a list (in a single row per root node):
MATCH p = (n:Root)-[rs1*]->()
WHERE ALL(rel in rs1 WHERE rel.relevance is null)
WITH n, relationships(p) AS rs
RETURN n, extract(r IN rs | type(r))
Or even shorter:
MATCH p = (n:Root)-[rs1*]->()
WHERE ALL(rel in rs1 WHERE rel.relevance is null)
RETURN n, extract(r IN relationships(p) | type(r))