Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Path in text format from Graph

Tags:

neo4j

cypher

In my graph I have data like following way.

Here a,b,c,d are nodes and r1,r2,r3,r4 are relations.

a-r1->b
b-r2->a
b-r2->c
c-r1->b
d-r3->a
a-r1->d like this.

I am using following Cypher to get path with max depth 3.

MATCH p=(n)-[r*1..3]-(m) WHERE n.id=1 and m.id=2  RETURN p 

Here return p is path and I want to display path in text format like this.

Example : Suppose Path Lengh is 3. a-r1->b-r2->c like this in text format.

Is this possible ?

like image 631
dotnetstep Avatar asked Feb 01 '26 22:02

dotnetstep


1 Answers

Sort of. I'll give you most of the answer, but I myself can't complete the answer. Maybe another cypher wizard will come along and improve on the answer, but here's what I've got for you.

match p=(n)-[r*1..3]-(m) 
WHERE id(n)=1 AND id(m)=2
WITH extract(node in nodes(p) | coalesce(node.label, "")) as nodeLabels,
     extract(rel in relationships(p) | type(rel)) as relationshipLabels
WITH reduce(nodePath="", nodeLabel in nodeLabels | nodePath + nodeLabel + "-") as nodePath,
     reduce(relPath="", relLabel in relationshipLabels | relPath + relLabel + "-") as relPath
RETURN nodePath, relPath
LIMIT 1;

EDIT - one small note, in your question you specify the WHERE criteria n.id=1 and m.id=2. Note that this is probably not what you want. Node IDs are usually checked with WHERE id(n)=1 AND id(m)=2. Id isn't technically a node property, so I changed that.

OK, so we're going to match the path. Then we're going to use the extract function to pull out the label property from nodes, and create a collection called nodeLabels. We'll do the same for the relationship types. What reduce does here is accumulate each of the individual strings in those collections down to a single string. So if your nodes are a, b, and c, you'd get a nodePath string that looks like a-b-c-. Similarly, your relationship string would look like r1-r2-r3-.

Now, I know you want those interleaved, and you'd prefer output like a-r1-b-r2-c. Here's the problem I see with that...

Normally, the way I'd approach that is to use FOREACH to iterate over the node label collection. Since you know there is one less relationship than nodes because of what paths are, ideally (in pseudo code) I'd want to do something like this:

buffer = ""
foreach x in range(0, length(nodeLabels)) | 
   buffer = buffer + nodeLabels[idx] + "-" + relLabels[idx] + "->")

This would be a way of reducing to the string that you want. You can't use the reduce function, because it doesn't provide you a way of getting which index you're at in the collection. Meaning that you can iterate over one of the collections, but not at the same time over the other. This FOREACH pseudo code will not work, because the second part of FOREACH I believe has to be a mutating operation on the graph, and you can't just use it to accumulate a string like I did here, or like the extract function does.

So as far as I can tell, you might kinda be stuck here. Hopefully someone will prove me wrong on this - I am not 100% sure.

Finally another way to go after this would be, if there was a path function that extracted node/relationship pairs, rather than just nodes() or relationships() individually as I used them above, then you could use that function to iterate over one collection, rather than shuffling two collections, as my code above attempts and fails to do. Sadly, I don't think there's any such path function, so that's just more reason why I think you might be up a creek.

Now, practically speaking, you could always execute this query in java or some other language, return the path, and then use the full power of whatever programming language you want to build up this string. But pure cypher? I'm doubtful.

like image 126
FrobberOfBits Avatar answered Feb 04 '26 16:02

FrobberOfBits



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!