cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

I understand (x)-[:REL|REL2]->(y) but is there a [:REL && REL2] equivalent?

Hi folks.

Pretty much a n00b and I have tried searching for questions about relationships but nothing seems relevant which suggests I'm not phrasing my search correctly

Hopefully, the title is self-explanatory.

Is there a pattern for matching a node that has not or another relationship from a set, but ALL the relationships from a set (actually only 2)?

I'm modelling software vulnerabilities and I'd like to find github repos that have both :hasSCAFindings and :hasSASTDefect relationships. If I wanted one or the other the [:x|y|z] approach would do what I want but I don't know where to go on this one.

I'm sure that like many things, it's simple once you know how, so any advice is greatly appreciated.

Many thanks!

7 REPLIES 7

see Predicate functions - Neo4j Cypher Manual and the usage of 'ANY'.

The below example, as I understand your question, should report all nodes which have 2 relationships, namely REL1 and REL2

//  1. create 3 nodes
create (n:N {id:1});
create (n:N {id:2});
create (n:N {id:3});

// create 2 relationships REL1 and REL2 for node w id=1
match (n:N {id:1}),(n2:N {id:2}) create (n)-[:REL1]->(n2);
match (n:N {id:1}),(n2:N {id:2}) create (n)-[:REL2]->(n2);

// create 1 relationship REL1 for node w id=2
match (n:N {id:2}),(n2:N {id:3}) create (n)-[:REL1]->(n2);

// create 2 relationships REL1 and REL3 for node w id=3
match (n:N {id:3}),(n2:N {id:2}) create (n)-[:REL1]->(n2);
match (n:N {id:3}),(n2:N {id:2}) create (n)-[:REL3]->(n2);

// create 5 relationships REL1, REL2, REL3, REL4, REL5 for node w id=2
match (n:N {id:2}),(n2:N {id:1}) create (n)-[:REL1]->(n2);
match (n:N {id:2}),(n2:N {id:1}) create (n)-[:REL2]->(n2);
match (n:N {id:2}),(n2:N {id:1}) create (n)-[:REL3]->(n2);
match (n:N {id:2}),(n2:N {id:1}) create (n)-[:REL4]->(n2);
match (n:N {id:2}),(n2:N {id:1}) create (n)-[:REL5]->(n2);

// show all start node, terminating node and the relationships between 2 node
match (n)-[r]->(n2) return n,n2,collect(r);


// report only those nodes which have a REL1 and a REL2
match (n)-[r]->() with n,collect(type(r)) as allRels 
where ANY (x IN allRels WHERE x = 'REL1'  ) AND 
            ANY (x IN allRels WHERE x ='REL2')  
return n,allRels;

and if you only want only thos node where they only have 2 relationships and they are REL1 and REL2 then

match (n)-[r]->() with n,collect(type(r)) as allRels
 where size(allRels)=2 and 
             ANY (x IN allRels WHERE x = 'REL1' ) AND 
             ANY (x IN allRels WHERE x ='REL2')  return n,allRels;

Tell me if i'm wrong:

MATCH ()<-[:hasSCAFindings]-(ghr:GithubRepo)-[:hasSASTDefect]->()
RETURN ghr

That's it, I don't think it has to be more complicated then that.

Yeah. My response may have over complicated

Over-complicated or not, it worked and it's a useful example of something that I would never have stumbled across on my own, so thank you for taking the time to reply

Thanks Tard! This also works and is a lot simpler to get my head around. Because of the way my if structured my data all my examples so far have just single directed relationships. I think that got me into thinking in a particular way, so this is an excellent example for me.

As the writing language is only left to right, you can add more then two relations to your ghr node like this if needed:

MATCH ()<-[:hasSCAFindings]-(ghr:GithubRepo)-[:hasSASTDefect]->(), (ghr)-[:hasNewRelation]->()

I didn't know that. Sounds like it'll be useful in the future. Thanks, Tard.