cancel
Showing results for 
Search instead for 
Did you mean: 

Validation for the each node in same path

raseemmd30
Node Link

I want to convert one gremlin query which is similar to below one. In repeat statement, it will traverse till EndNode with validating each InNode1 in that path with given conditions.

If any InNode1 in that path doesnt satisfy then result will be Zero.

g.V().hasLabel('Person').has('name','John')
.repeat(.out('OutNode1').in('InNode1').has('Status',within('Active','InActive'))
.not(has('oStatus',within('Suspended','Closed'))).where(
.out('OutNode2').not(has('name',within('SampleVal1','SampleVal2'))))
)
.until(__.in('MeetsEndNode'))
.in('MeetsEndNode')

I converted above query into cypher like below. Here filtering applies to last node in that path. It is not checking all InNode1 in that path.

MATCH (p:Person {name: 'John'}) - [:OutNode1|InNode1*] - (relNode) <-[:MeetsEndNode]-(endNode)
WHERE relNode.Status in ['Active','InActive']
AND NOT relNode.oStatus in ['Suspended','Closed']
AND NOT exists { MATCH (relNode) - [:OutNode2] -> (o)
WHERE o.name in ['SampleVal1','SampleVal2'] }
RETURN endNode

Please suggest how we can achieve the same functionality in cypher.

8 REPLIES 8

giuseppe_villan
Graph Fellow

@raseemmd30

I think this should be work (I put (relNode)-[:OutNode2]->(o) in first match clause):

MATCH (p:Person {name: 'John'})-[:OutNode1|InNode1*]-(relNode)<-[:MeetsEndNode]-(endNode), (relNode)-[:OutNode2]->(o)
WHERE relNode.Status in ['Active','InActive']
AND NOT relNode.oStatus in ['Suspended','Closed']
AND NOT o.name in ['SampleVal1','SampleVal2']
RETURN endNode

@giuseppe.villani ... Thanks for your response.

I am simplifying my query . Below screen shot shows the how data model looks like

If any of the InNode in that path fails with given below validation then last InNode should not come in the result set. If all InNode in that path passed with all validations then FInal InNode should come in the result.

MATCH (n:Person {name:'John'}) -  [:OutNode|InNode*] - (InNode) 
WHERE InNode.Status in ['Active','InActive']
AND NOT InNode.oStatus in ['Suspended','Closed']
AND NOT exists { MATCH (InNode) - [:SubOutNode] -> (o) WHERE o.name in ['SampleVal1','SampleVal2'] }

Above code checks only the last InNode of that path. If last InNode passed with validation then it is giving the result. It is not checking all the InNodes present in the path. Kindly suggest how we can achieve this.

You'll need to use a path variable and the all() list predicate on the list of nodes in the path.

For example:

MATCH path = (n:Person {name:'John'}) -  [:OutNode|InNode*] -()<-[:MeetsEndNode]-(endNode) 
WHERE all(node IN nodes(path) WHERE node.Status in ['Active','InActive'] AND NOT node.oStatus in ['Suspended','Closed'] 
 AND NOT exists { 
    MATCH (node) - [:OutNode2] -> (o)
    WHERE o.name in ['SampleVal1','SampleVal2'] })
RETURN endNode

Though returning the path itself may be more useful for you.

You can also bound the nodes that are evaluated to exclude the first and last nodes of the path, so they apply to the nodes in the middle only:

...
WHERE all(node in nodes(path)[1..-1] WHERE ...
...

THAT SAID...I'm encountering syntax errors when trying to use existential subqueries within list predicates, something that seems buggy to me. I'm following up with that internally.

@andrew.bowman Thanks for your prompt response.

As you rightly mentioned, syntax error occuring when we use Not exists within list predicates. If i remove Not exists then query is executing without any errors and validating the node as expected.

MATCH path = (n:Person {Name:'John'}) -  [:OutNode|InNode*] -()-[:EndNode]->(endNode) 
WITH path,[i in nodes(path) where 'InNode' in labels(i)] as InNodes
WHERE ALL  (i IN InNodes WHERE i.Status in ['Active','InActive'] AND NOT i.oStatus in ['Suspended','Closed']  AND NOT exists { 
    MATCH (i) - [:OutNode2] -> (o)
    WHERE o.name in ['SampleVal1','SampleVal2'] }) 
RETURN path

Error is

Please let us know if you know any alternative for this error or any update from your internal team

Below query is working with relationship check (i)-[:OutNode2] -> () in list predications but not able to filter the relationship node with some condition like (i)-[:OutNode2] -> (o) WHERE o.name in ['SampleVal1','SampleVal2']

MATCH path = (n:Person {Name:'John'}) -  [:OutNode|InNode*] -()-[:EndNode]->(endNode) 
WITH path,[i in nodes(path) where 'InNode' in labels(i)] as InNodes
WHERE ALL  (i IN InNodes WHERE i.Status in ['Active','InActive'] AND NOT i.oStatus in ['Supended','Closed'] AND (i)-[:OutNode2] -> ()  )  
RETURN path

Still waiting to hear back if this syntax error is a bug.

We may be able to do a workaround with pattern comprehensions instead. Something like:

MATCH path = (n:Person {Name:'John'}) -  [:OutNode|InNode*] -()-[:EndNode]->(endNode) 
WITH path,[i in nodes(path) where 'InNode' in labels(i)] as InNodes
WHERE ALL  (i IN InNodes WHERE i.Status in ['Active','InActive'] AND NOT i.oStatus in ['Suspended','Closed']  
  AND size([(i) - [:OutNode2] -> (o) WHERE o.name in ['SampleVal1','SampleVal2'] | 1]) = 0)
RETURN path

The pattern comprehension lets us express the limitations on the other node, o, and if the size of the list from that comprehension is 0, that means no such matches were found.

@andrew.bowman Is there any update from your internal team on this issue ?
I have divided the condition into three parts for time being and it is working. I cannot do like this if more conditions getting added in other areas.

MATCH path = (n:Person {Name:'John'}) -  [:OutNode|InNode*] -() 
-[:EndNode]->(endNode) 
WITH path,[i in nodes(path) where 'InNode' in labels(i)] as InNodes
WHERE ALL  (i IN InNodes WHERE i.Status in ['Active','InActive'] 
AND NOT i.oStatus in ['Suspended','Closed']  
 AND (i) - [:OutNode2] -> () 
 AND NOT  (i) - [:OutNode2] -> ( {name:'SampleVal1'})
 AND NOT  (i) - [:OutNode2] -> ( {name:'SampleVal2'}) )

Sorry, nothing new to report here. At this time please continue to use the workaround provided.