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

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.

Related

neo4j turn paths into subgraph

Say I have the following graph
Z
/ \
/ \
A -> B -> C -> D
\ /
-> X -> Y
I compute the paths
match p=((:A)-[*]->[:D])
return p
This will return three paths (rows): AZD, ABCD and AXYD
But I would like to return a subgraph that contains all the paths between A and D. so the result should be a subgraph. My understanding is that the only format for a subgraph return is nodes and relationships. So a query like below
// query logic
return nodes, relationships
What should I write in the query logic? NOTE:
this is not the entire graph, there are other subgraphs in my graph, so returning the entire graph does not work
A and D are just node types here, there will be many type A and type D nodes and there will be one or multiple paths between each A and D node pair.
One way to retrieve the unique set of nodes and relationships is using apoc
MATCH p=((:A)-[*]->(:D))
RETURN apoc.coll.toSet(
apoc.coll.flatten(
COLLECT(nodes(p))
)
) AS nodes,
apoc.coll.toSet(
apoc.coll.flatten(
COLLECT(relationships(p))
)
) AS relationships

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.

Neo4J Cypher - Unwinding nodes from a path variable

I have seen examples of unwinding lists, but not of unwinding a list of paths. How can I find, for example, all of the shortest paths between one type of node and another, and return or get the nodes that are found, in this example the nodes specifically being b.
MATCH p = allShortestPaths((a: person)-[:PARENT_OF]-(b: person))
UNWIND nodes(p) ... //get all of the b nodes
RETURN b
Note: I would like to use b within the query for another purpose (omitted), and therefore need to unwind the path into a list of b nodes.
After matching all shortest paths, if you just want the b nodes as a result, you may simply RETURN b. I don't believe you need to UNWIND it, since b is clearly identified in your MATCH
Edit:
MATCH p = allShortestPaths((a: person)-[:PARENT_OF]-(b: person))
WITH collect(b) as bees
UNWIND bees as b
//do something
return b
It seems like you just want to see all person nodes that have an incoming PARENT_OF node from another person node. If so, this should work:
MATCH ()-[:PARENT_OF]->(b:person)
RETURN DISTINCT b;
MATCH p = allShortestPaths((a: person)-[:PARENT_OF]-(b: person))
with nodes(p) as nodes
with nodes[size(nodes)-1] as b
return b

Cypher : Return Nodes that matched along with Nodes that didn't match

With Labels A, B, and Z, A and B have their own relationships to Z. With the query
MATCH (a:A)
MATCH (b:B { uuid: {id} })
MATCH (a)-[:rel1]->(z:Z)<-[:rel2]-(b)
WITH a, COLLECT(z) AS matched_z
RETURN DISTINCT a, matched_z
Which returns the nodes of A and all the Nodes Z that have a relationship to A and B
I'm stuck on trying to ALSO return a separate array of the Z Nodes that B has with Z but not with A (i.e. missing_z). I am attempting to do an initial query to return all the relationships between B & Z
results = MATCH (b:B { uuid: {id} })
MATCH (b)-[:rel2]->(z:Z)
RETURN DISTINCT COLLECT(z.uuid) AS z
MATCH (a:A)
MATCH (b:B { uuid: {id} })
MATCH (a)-[:rel1]->(z:Z)<-[:rel2]-(b)
WITH a, COLLECT(z) AS matched_z, z
RETURN DISTINCT a, matched_z, filter(skill IN z.array WHERE NOT z.uuid IN {results}) AS missing_z
The results seem to have nil for missing_z where one would assume it should be populated. Not sure if filter is the correct way to go with a WHERE NOT / IN scenario. Can the above 2 queries be combined into 1?
The hard part here, in my opinion, is that any failed matches will drop everything you have matched so far. But your starting point seems to be "All Z related by B.uuid", So start by collecting that and filtering/copying from there.
Use WITH + aggregation functions to copy+filter columns
Use OPTIONAL MATCH if a failure to match shouldn't drop already collected rows.
If I understand what you are trying to do well enough, This cypher should do the job, and just adjust it as needed (let me know if you need help understanding any part of it/adapting it)
// Match base set
MATCH (z:Z)<-[:rel2]-(b:B { uuid: {id} })
// Collect into single list
WITH COLLECT(z) as zs
// Match all A (ignore relation to Zs)
MATCH (a:A)
// For each a, return a, the sub-list of Zs related to a, and the sub-list of Zs not related to a
RETURN a as a, FILTER(n in zs WHERE (a)-[:rel1]->(n)) as matched, FILTER(n in zs WHERE NOT (a)-[:rel1]->(n)) as unmatched
This query might do what you want:
MATCH (z:Z)<-[:rel2]-(b:B { uuid: {id} })
WITH COLLECT(z) as all_zs
UNWIND all_zs AS z
MATCH (a)-[:rel1]->(z)
WITH all_zs, COLLECT(DISTINCT z) AS matched_zs
RETURN matched_zs, apoc.coll.subtract(all_zs, matched_zs) AS missing_zs;
It first stores in the all_zs variable all the Z nodes that have a rel2 relationship from b. This collection's contents remain unaffected even if the second MATCH clause matches a subset of those Z nodes.
It then stores in matched_zs the distinct all_zs nodes that have a rel1 relationship from any A node.
Finally, it returns:
the matched_zs collection, and
the unique nodes from all_zs that are not also in matched_zs, as missing_zs.
The query uses the convenient APOC function apoc.coll.subtract to generate the latter return value.

Getting nodes from paths

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

Resources