langlauf.io
langlauf.io

Reputation: 3191

Neo4j cypher query: Exclude subpaths from MATCH

I would like to match certain paths in my graph. These good paths should not contain certain subpaths, e.g. avoiding certain nodes. For example, given the graph

a->b->c->d
a->avoid1->b
c->avoid2->d

NB: There could be many more nodes in between the edges I specified, e.g. a->t0->t1->b or a->avoid1->t2->b.

Now I would like to get all paths from a to d which do not contain certain subpaths, to be precise, those subpaths going from a over avoid1 to b and from c over avoid2 to d.

My current (insufficient) approach is to MATCH the entire path I am looking for and then specifying the node I want to avoid:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT (avoid1 IN nodes(p))

This is not working out for me because I actually need to "filter out" subpaths and not nodes.

I need something like this:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(avoid1)->[:CF*]->(b) IN p) AND NOT ( (c)-[:CF*]->(avoid2)->[:CF*]->(d) )

This does not work, I know but it could help to explain what I need: a way to filter out paths based on the fact if they contain certain subpaths.

EDIT:

Here are the commands:

MERGE (a:MYTYPE { label:'a' })
MERGE (b:MYTYPE { label:'b' })
MERGE (c:MYTYPE { label:'c' })
MERGE (d:MYTYPE { label:'d' })
MERGE (avoid1:MYTYPE { label:'avoid1' })
MERGE (avoid2:MYTYPE { label:'avoid2' })

CREATE (a)-[:CF]->(b)
CREATE (b)-[:CF]->(c)
CREATE (c)-[:CF]->(d)

CREATE (a)-[:CF]->(avoid1)
CREATE (avoid1)-[:CF]->(b)
CREATE (c)-[:CF]->(avoid2)
CREATE (avoid2)-[:CF]->(d)

and my current try (as suggested by dave's answer):

MATCH (a:MYTYPE { label:'a' })
MATCH (b:MYTYPE { label:'b' })
MATCH (c:MYTYPE { label:'c' })
MATCH (d:MYTYPE { label:'d' })
MATCH (avoid1:MYTYPE { label:'avoid1' })
MATCH (avoid2:MYTYPE { label:'avoid2' })

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(avoid1 {label:'avoid1'})-[:CF*]->(b) ) 

RETURN p

Yet, this gives me "(no rows)".

Upvotes: 1

Views: 764

Answers (1)

Dave Fauth
Dave Fauth

Reputation: 878

This query should allow you to filter on paths:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->()-[:CF*]->(b)) 
AND NOT ( (c)-[:CF*]->()-[:CF*]->(d) )
return p;`

You could also specify a label/property for the node that you want to filter on:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(:Person {name:'Dave'})-[:CF*]->(b)) AND NOT ( (c)-[:CF*]->()-[:CF*]->(d) )
return p;

Upvotes: 1

Related Questions