Home > Enterprise >  Neo4j Cypher Single Query to WHERE variables "may" appear in different patterns
Neo4j Cypher Single Query to WHERE variables "may" appear in different patterns

Time:10-13

I have a graph of parent-children objects related by [IS_A] that may be related to each other [HAS]:
Graph Example

Assuming properties are inherited by children. I want to create a single Query that could answer ALL the Questions:
Do card tables have a base? - (l {name:'card table'})-[:IS_A*]->(m)-[:HAS]->(n)-[:IS_A*]->(o {name:'base'})
Do card tables have a leg? - (l {name:'card table'})-[:IS_A*]->(m)-[:HAS]->(o {name:'leg'})
Does furniture have a base? - (l {name:'furniture'})-[:HAS]->(n)-[:IS_A*]->(o {name:'base'})
Does furniture have a leg? - (l {name:'furniture'})-[:HAS]->(o {name:'leg'})

NOT knowing what pattern my objects will match I want to test them all at once in one Query. This is the query that makes sense to me but does not work:

MATCH (l {name:'X'}), (m), (n), (o {name:'Y'})
WHERE (l)-[:IS_A*]->(m)-[:HAS]->(n)-[:IS_A*]->(o) OR (l)-[:IS_A*]->(m)-[:HAS]->(o) OR (l)-[:HAS]->(n)-[:IS_A*]->(o) OR (l)-[:HAS]->(o)
RETURN l, m, n, o

One by one the Where's work. BUT all together I get EVERY node and relation in my DB!

CodePudding user response:

OH man I am a ding-a-ling I should ONLY RETURN l, o
IF I return m, n and m, n are NOT children of the query then I am indirectly asking for everything.

So the correct query is: MATCH (l {name:'X'}), (m), (n), (o {name:'Y'})
WHERE (l)-[:IS_A*]->(m)-[:HAS]->(n)-[:IS_A*]->(o) OR (l)-[:IS_A*]->(m)-[:HAS]->(o) OR (l)-[:HAS]->(n)-[:IS_A*]->(o) OR (l)-[:HAS]->(o)
RETURN l, o

IF I get ANY nodes returned the answer is YES else NO

CodePudding user response:

A better approach may be to find, for a characteristic, all descendants, and for those descendants, all possessors. Those will be the pool of things that have that characteristic:

 (characteristic)<-[:IS_A*0..]-(descendent)<-[:HAS]-(possessor)

You can aggregate these (or use a pattern comprehension so they're in a list already)

Now, for your given item under test, all you have to do is see if it has any ancestors that are in the list of possessors.

We can use LIMIT 1 to make it quicker, since we only need to stop at the first match found.

MATCH (characteristic:Thing {name:$characteristic}), (thing:Thing {name:$thing})

WITH characteristic, thing, 
 [(characteristic)<-[:IS_A*0..]-(descendent)<-[:HAS]-(possessor) | possessor] as possessors

MATCH path = (thing)-[:IS_A*0..]->(ancestor)
WHERE ancestor IN possessors
RETURN ancestor
LIMIT 1
  • Related