0

Is it possible to write a Cypher query with a variable-length patter, that specifies that nodes between the start and end node can only be nodes with a certain property?

I think that a query like the following would match all of the below patterns:

MATCH p=(n:Node {foo:"True"})<-[:REL*0..2]-(:Node)<-[:REL]-(:Node {bar:"True"})

(n:Node {foo:"True"})                                        <-[:REL]-(:Node {bar:"True"})
(n:Node {foo:"True"})                    <-[:REL]-(:Node)    <-[:REL]-(:Node {bar:"True"})
(n:Node {foo:"True"})  <-[:REL]-(:Node)  <-[:REL]-(:Node)    <-[:REL]-(:Node {bar:"True"})

I imagine it "copying" the <-[:REL]-(:Node) part of the query 0 to 2 times in between the (n:Node {foo:"True"}) and <-[:REL]-(:Node {bar:"True"}) query parts and constructing some kind of UNION of the matches.

Is this the right way to think about it? And how would i make the variable-lenght query match only paths where the middle nodes have the property {bar:"True"} in the middle nodes like so:

(n:Node {foo:"True"})                                                    <-[:REL]-(:Node {bar:"True"})
(n:Node {foo:"True"})                          <-[:REL]-({bar:"True})    <-[:REL]-(:Node {bar:"True"})
(n:Node {foo:"True"})  <-[:REL]-({bar:"True})  <-[:REL]-({bar:"True})    <-[:REL]-(:Node {bar:"True"})

Would the query below be the right approach?

MATCH p=(n:Node {foo:"True"})<-[:REL*0..2]-(:Node {bar:"True"})<-[:REL]-(:Node {bar:"True"})

It appears to me that this is not the case. Can somebody clearify on where I am going wrong in my thinking process?

4
  • 1
    You can use APOC with nodes filter: neo4j.com/labs/apoc/4.0/graph-querying Commented Apr 7, 2022 at 15:29
  • It'd be easy if "bar" was a label or property of the relationship - if that's compatible with your data model. Commented Apr 7, 2022 at 16:25
  • @DavidPond unfortunately it is only a node property - like in my example given, but please feel free to provide a solution if the property were of the relationship (although for my case it is not usable) Commented Apr 7, 2022 at 16:27
  • @nimrodserok My question still remains...How can I think about the variable-length pattern. And is my assumption correct? Commented Apr 7, 2022 at 16:28

2 Answers 2

1
MATCH path=(:Node {foo:True})-[:REL*0..2]-(n:Node {bar:True})
WHERE all(x in nodes(path) WHERE x.bar=True OR x.foo=True)
RETURN n.name
Sign up to request clarification or add additional context in comments.

Comments

0

I think it'd be easy if foo were a relationship property, instead of a node property.

Create a simple example:

MERGE (a:Node {name:"a", foo:True})
MERGE (b:Node {name:"b", bar:True})
MERGE (c:Node {name:"c", bar:True})
MERGE (d:Node {name:"d", bar:False})
MERGE (e:Node {name:"e", bar:True})
MERGE (a)<-[:REL]-(b)
MERGE (b)<-[:REL]-(c)
MERGE (a)<-[:REL]-(d)
MERGE (d)<-[:REL]-(e)

I think you want to match nodes b and c, but not e because we'd have to traverse d which has foo:False.

Make bar a property on the relationships:

MATCH ()<-[r:REL]-(n:Node)
SET r.bar = n.bar

Now you can write:

MATCH (:Node {foo:True})<-[:REL*0..2 {bar:True}]-(n:Node)
RETURN n.name

Which returns b and c as required.

1 Comment

Looks easy and definitely works! BUT my dataset is about 150 million nodes and I dont want to change the relationships this way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.