Michael Oryl
Michael Oryl

Reputation: 21652

Neo4j query with logical AND on relationship types instead of OR

UPDATE: I've changed the graphic and example queries to make the request more clear. The basic idea is the same, but now I'm showing that there really are more than just two relationships. The idea is I want TWO of them to match, not necessarily ALL of them.

Given the following Neo4j graph:

Two nodes with many relationships

Is it possible to specify a relationship in a query that requires that TWO specific relationships be there for a match, but not necessarily all, without simply stating each full matching path separately? I want a logical AND on the relationship types, just like we have a logical OR using the | character.

This is how you would use a logical OR with the | character:

// OR on MEMBER_OF and GRANT_GROUP_COMP
MATCH (p:Person {name:'John'})-[r:MEMBER_OF|GRANT_GROUP_COMP]->(t:Team {name:'Team 1'})
RETURN p,r,t

What I'm looking for is something like this, an AND with a & or simlar that REQUIRES that both relationships be present:

// AND type functionality in the relationship I'd like
MATCH (p:Person {name:'John'})-[r:MEMBER_OF&GRANT_GROUP_COMP]->(t:Team {name:'Team 1'})
RETURN p,r,t

Without having to resort to this - which works for me just fine:

// I'd like to avoid this
MATCH (p:Person {name:'John'})-[r:MEMBER_OF]->(t:Team {name:'Team 1'}),
  (p)-[r2:GRANT_GROUP_COMP]->(t)
RETURN p,r,r2,t

Any insight would be appreciated, but based on responses so far, it simply doesn't exist.

Upvotes: 4

Views: 648

Answers (3)

cybersam
cybersam

Reputation: 66999

This query will return a result if John and Team 1 have MEMBER_OF AND GRANT_GROUP_COMP relationships between them.

(This is very similar to the second answer of @stdob--, but requires the size of types to be exactly 2.)

MATCH (p:Person {name: 'John'})-[r:MEMBER_OF|GRANT_GROUP_COMP]->(t:Team {name: 'Team 1'})
WITH p, t, COLLECT(r) AS rels, COLLECT(DISTINCT type(r)) AS types
WHERE SIZE(types) = 2
RETURN p, t, rels;

Upvotes: 2

Dave Bennett
Dave Bennett

Reputation: 11216

You could add the second relationship type in a WHERE clause. Something like this...

MATCH (p:Person {name:'John'})-[r:GRANT_GROUP_COMP]->(t:Team {name:'Team 1'})
WHERE (p)-[:MEMBER_OF]->(t)
RETURN *

Or you could make sure that the complete set is in the collection of relationship types. Something like this...

MATCH (p:Person {name:'John'})-[r]->(t:Team {name:'Team 1'})
with p,t,collect(type(r)) as r_types
where all(r in ['MEMBER_OF','GRANT_GROUP_COMP'] where r in r_types)
RETURN p, t, r_types

Upvotes: 1

stdob--
stdob--

Reputation: 29172

What about this?

MATCH (D:Person {name:'Donald'})-[r1:WORKS_AT]->
      (o:Office {code:'279'})<-[r2:SUPPORTS]-(D)
RETURN *

Inspired version of Dave

MATCH (D:Person {name:'Donald'})-[r:WORKS_AT|SUPPORTS]->(o:Office {code:'279'})
WITH D, o, collect(r) as rels, 
     collect(distinct type(r)) as tmp WHERE size(tmp) >= 2
return D, o, rels

Update:

MATCH (D:Person {name:'Donald'})
      -  [r: MEMBER_OF
           | GRANT_INDIRECT_ALERTS
           | GRANT_INDIRECT_COMP
           | GRANT_GROUP_ALERTS
           | GRANT_GROUP_COMP 
         ] ->
      (o:Office {code:'279'})
WITH D, o, collect(r) as rels, 
     collect(distinct type(r)) as tmp WHERE size(tmp) >= 2 AND size(tmp) <= 5
return D, o, rels

Upvotes: 3

Related Questions