Getting nodes from paths - neo4j

I have a path that returns a number of, well, paths. nodes(path) looks like:
[a, b, c, d],
[a, b, e],
[a, f]
What I want is to get all the nodes. So converting that path to
a
b
c
d
e
f
would be great. I would like to continue using the nodes in further cypher statements so leaving them in a collection doesn't work for me.
Any ideas?
EDIT 1
MATCH(t:THING1 {id:"t1"})-[:AFFECTS]->(x:SOME_NODE), (t)-[:CHANGES]->(SOME_NODE)
MATCH p=shortestpath((s)-[MY_RELATION*0..4]->(x))
WITH collect(nodes(p)) as nodes
WITH REDUCE(output = [], r IN nodes | output + r) AS flat
This produces a collection of nodes. Now to convert it into rows and dedup it...

You could just unwind the collections of nodes from the paths and then return the distinct ones.
MATCH(t:THING1 {id:"t1"})-[:AFFECTS]->(x:SOME_NODE), (t)-[:CHANGES]->(SOME_NODE)
MATCH p=shortestpath((s)-[MY_RELATION*0..4]->(x))
UNWIND nodes(p) as n
RETURN DISTINCT n

Related

Get end nodes when using *

Lets say I have points a, b, c, d and a->b->c->d is related with next. Below is merge command for it.
merge (a:point{id:'a'})-[:next]-(b:point{id:'b'})-[:next]-(c:point{id:'c'})-[:next]-(d:point{id:'d'}) return a, b, c, d
Neo4j image of the merge
What I am looking for is a way to get all the points between a and d. Using below query I get the relationships, but how can I get list that contains b, c?
match p=(start:point)-[:next*]-(end:point)
with *, relationships(p) as r
where start.id ='a' and end.id = 'd'
return start, r, end
You can do
RETURN nodes(p)[1..-1]
to get the nodes except the first and last one.

Query to write hops and return all the properties from the middle nodes or a better way to do it and skip hops?

Node A is connected to Node E through different nodes B (B can be repeating), C and D etc as given below.
(A)--(C)--(D)--(E)
(A)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(B)--(C)--(D)--(E)
There could be up to 7 B nodes between A and C or no B node at all (like the first case above).
Question: How to get all the E1, E2, E3, E4 connected to A1 with a single query and return properties from all A, B, C, D and E nodes? I could not return the properties using the hops.
MATCH (A {Id:30})-[*1..6]-(E) RETURN DISTINCT A.Name, E.Name;
But we want to return B.Name (If there are multiple B nodes in the middle their names too), C.Name and D.Name too. Happy to skip hopping completely if required. Help please? Thanks in advance.
Try this
// in case there is always A,C and E, you can look for
// paths with length 3 to 6
MATCH path=(A)-[*3..6]-(E)
// return the name of each node in the same order
RETURN [n IN nodes(path) | n.name] AS nodeNames
Assuming A through E are node labels, this query should get all paths that match your pattern (with 0 to 7 B nodes between the A and C nodes), and return distinct lists of node Name values:
MATCH p=(:A)-[*..8]-(:C)--(:D)--(:E)
WHERE ALL(n IN NODES(p)[1..-3] WHERE 'B' IN LABELS(n))
RETURN DISTINCT [m IN NODES(p) | m.Name] AS names
In general, the query would be more efficient if you could also specify the relationship types and their directionality.

How do you find all nodes with exactly N relationships of a single type?

I have some nodes A connected to nodes B via a relationship rel. What query will I write to return all B which are related to exactly 3 A or exactly 4 A or exactly n A via the relation rel? I achieved this for 2 by using the following match clause:
MATCH (a1:A)<-[:rel]-(b:B)-[:rel]->(a2:A)
I also require to know which 3 A are connected to that B as I need to count the occurrences of that set of 3 A
You can aggregate by COUNT:
MATCH (b:B)-[:rel]->(a:A)
WITH b, count(a) AS cnt WHERE cnt = 3 // or for example WHERE cnt IN [3, 4]
RETURN b
Upd: Try to use the COLLECT and SIZE functions if you need to return nodes connected to (:B):
MATCH (b:B)-[:rel]->(a:A)
WITH b,
collect(a) AS nds WHERE size(nds) = 3
RETURN b, nds
I guess it can be shorter
MATCH (b:B)
WHERE size((b)-[:rel]->(:A)) = 3
RETURN b,[(b)-[:rel]->(a:A) | a ] AS nds

How to find all multi-directional relations between two nodes?

I'm trying to find all relations between node a and node b, and the relations could be multi-directions. For example,
a <- c -> b or a -> d -> b where c and d are nodes.
I've tried MATCH (a:PERSON {name: 'WD'})-[r*..3]-(b:PERSON{name: 'EK'}) RETURN r, a, b, but I got two isolated nodes, because the relation between a and b is: a <- c -> b.
Any help would be appreciated.
You can return the path if you need all the relationships and nodes in between.
Following query will
You can modify your query to return full paths instead of just nodes a and b as following:
MATCH paths=(a:PERSON {name: 'WD'})-[r*..3]-(b:PERSON{name: 'EK'})
RETURN paths
This will return paths of length up to 3, change it as you need.

Neo4J: Return only the candidates, not all the combinations

Consider a Cypher query in the following form:
MATCH a-->b,a-->c,a-->d WHERE [some conditions on a, b, c and d] RETURN id(a),id(b),id(c),id(d)
The query above, probably as expected, will return all the combinations of candidate nodes for a, b, c, and d. So, for instance, if there are three candidates for b and four candidates for c, the total number of rows returned by the query will be 3 x 4 = 12. How can it be adjusted so the different matching nodes for each alias (a to d) is returned only once?
The following query is not a valid one, but should clarify what I have in mind:
MATCH a-->b,a-->c,a-->d WHERE [some conditions on a, b, c and d] RETURN distinct id(a), distinct id(b), distinct id(c), distinct id(d)
You can use distinct aggregation.
MATCH a-->b,a-->c,a-->d
WHERE [some conditions on a, b, c and d]
RETURN collect(distinct id(a)) as ids_a,collect(distinct id(b)) as ids_b,
collect(distinct id(c)) as ids_c,collect(distinct id(d)) as ids_d;

Resources