Reputation: 342
I want to get all the nodes and relationships in a path in following format: node1, node2, relationship-type, relationship-direction.
I tried getting path using this query. From this I can get nodes and relationships. But cannot get the directions of relationships.
MATCH path = (e1:Entity)-[rel*1..4]-(e2:Entity)
WHERE e1._id = "222" AND e2._id = "777"
RETURN path
I want the result to be similar to output of the following query which returns direct relationships.
MATCH (e1:Entity) WHERE e1._id = "222"
MATCH (e2:Entity) WHERE e2._id = "333"
MATCH (e1)-[rel]-(e2)
RETURN e1, e2, type(rel), (startNode(rel) = e1) as isOut
Upvotes: 1
Views: 864
Reputation: 5057
It can be done, but I could not find a simple solution. So let's go with the complicated one.
First, create an example graph:
CREATE
(a:Entity {name: 'a'}),
(b:Entity {name: 'b'}),
(c:Entity {name: 'c'}),
(d:Entity {name: 'd'}),
(e:Entity {name: 'e'}),
(a)-[:REL {name: 'r1'}]->(b)
<-[:REL {name: 'r2'}]-(c)
-[:REL {name: 'r3'}]->(d)
-[:REL {name: 'r4'}]->(e)
Use this query:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, isOutFirst, collect(isOut) AS isOuts
RETURN e1, e2, [isOutFirst] + isOuts AS isOuts
The result is:
╒═════════╤═════════╤═════════════════════════╕
│e1 │e2 │isOuts │
╞═════════╪═════════╪═════════════════════════╡
│{name: a}│{name: e}│[true, false, true, true]│
└─────────┴─────────┴─────────────────────────┘
The main ideas are the following:
extract
method.range
function and UNWIND
to generate a list of indexes and "iterate" on the lists.isOut
) if it starts from any node of the previous (i-1.) relationship.isOutFirst
).isOut
values to an isOuts
list.isOutFirst
variable and the isOuts
list to a single list.You can UNWIND
the results and add the corresponding relationship types:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2, rels,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, rels, isOutFirst, collect(isOut) AS isOuts
WITH e1, e2, rels,
[isOutFirst] + isOuts AS isOuts,
range(0, size(rels)-1) AS indexes2
UNWIND indexes2 AS i
RETURN e1, e2, type(rels[i]) AS relType, isOuts[i] AS isOut
This results in:
╒═════════╤═════════╤═══════╤═════╕
│e1 │e2 │relType│isOut│
╞═════════╪═════════╪═══════╪═════╡
│{name: a}│{name: e}│REL │true │
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │false│
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │true │
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │true │
└─────────┴─────────┴───────┴─────┘
Update: you can use the direction to extract the nodes in the correct order from the path:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2, rels,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, rels, isOutFirst, collect(isOut) AS isOuts
WITH e1, e2, rels,
[isOutFirst] + isOuts AS isOuts,
range(0, size(rels)-1) AS indexes2
UNWIND indexes2 AS i
RETURN e1, e2, type(rels[i]) AS relType,
CASE isOuts[i]
WHEN true THEN startNode(rels[i])
ELSE endNode(rels[i])
END AS node1,
CASE isOuts[i]
WHEN true THEN endNode(rels[i])
ELSE startNode(rels[i])
END AS node2
This results in:
╒═════════╤═════════╤═══════╤═════════╤═════════╕
│e1 │e2 │relType│node1 │node2 │
╞═════════╪═════════╪═══════╪═════════╪═════════╡
│{name: a}│{name: e}│REL │{name: a}│{name: b}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: b}│{name: c}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: c}│{name: d}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: d}│{name: e}│
└─────────┴─────────┴───────┴─────────┴─────────┘
Limitations: the solutions above might not work if there is a 2-length circle in the graph, e.g. for a graph (a)<-[r1]-(b)<-[r2]-(a)
, they incorrectly mark (b)<-[r2]-(a)
as outgoing for one of the paths.
Upvotes: 1
Reputation: 342
Seems my question was not clear.Sorry for that. Based on the previous answer I was able to get the relationships with nodes as follows for my use-case. In here I do not need isOut column since start and end nodes are there.
MATCH (e1 {_id: '222'})-[rels*1..4]-(e2 {_id: '777'})
WITH range(0, size(rels)-1) AS indexes,rels
UNWIND indexes AS i
RETURN startNode( rels[i]), type(rels[i]),endNode( rels[i])
Upvotes: 0