David McHealy
David McHealy

Reputation: 2481

Multiple optional matches in a cypher query, one doesn't match, not sure why

I have been modeling some data related to call paths. A call enters the system, then maybe someone answers, then someone transfers, then someone hangs up, maybe some other stuff happens in between. Since they are ordered from beginning to end, I decided to model them as a linked list:

(call:Call)-[r:NextEvent]->(e:Event)-[r:NextEvent]->(e:Event)

and so on for as many events as there are. To query all the events that happen on a call I can go:

neo4j-sh (?) $ match (call:Call)-[:NextEvent*]->(lastEvent:Event) where call.callid="123"
>              return lastEvent;
+------------------------------------------------------------------------------------------------------+
| lastEvent                                                                                            |
+------------------------------------------------------------------------------------------------------+
| Node[22]{name:"Newcall",callerid:"1231231234",calleridname:"David Foo",destination:"3213214321"}     |
| Node[24]{name:"EnterQueue"}                                                                          |
| Node[27]{name:"RingAttempt"}                                                                         |
+------------------------------------------------------------------------------------------------------+

That's pretty much perfect. When someone enters a queue, I'd like to know what queue they are in, and when a ring attempt is made, I'd like to know the user whose phone rang, so I added some relations.

neo4j-sh (?)$ match (e:Event)-[r:Agent]->(agent:User) where e.name="RingAttempt" return e,agent;        
+-----------------------------------------------------------------------------------------------------------------------------------+
| e                            | agent                                                                                              |
+-----------------------------------------------------------------------------------------------------------------------------------+
| Node[27]{name:"RingAttempt"} | Node[26]{username:"[email protected]"} |
+-----------------------------------------------------------------------------------------------------------------------------------+

neo4j-sh (?)$ match (e:Event)-[r:Queue]->(queue:Queue) where e.name="EnterQueue" return e,queue; 
+-------------------------------------------------------------------+
| e                           | queue                               |
+-------------------------------------------------------------------+
| Node[24]{name:"EnterQueue"} | Node[17]{name:"Main Support Queue"} |
+-------------------------------------------------------------------+

Now I'd like to run a query that will get each event, and if the event is a ringattempt, also give me the agent it attempted to ring, and if the event is an enterqueue, give me the queue that was entered, so I tried to write this:

neo4j-sh (?)$ match p = (call:Call)-[:NextEvent*]->(lastEvent:Event) where call.callid="123"
>             optional match (lastEvent)-[r:Queue]->(queue:Queue) where lastEvent.name="EnterQueue"
>             optional match (lastEvent)-[r:Agent]->(agent:User) where lastEvent.name="RingAttempt"
>             return lastEvent,queue,agent;
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| lastEvent                                                                                            | queue                               | agent  |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| Node[22]{name:"Newcall",callerid:"1231231234",calleridname:"David Foo",destination:"3213214321"}     | <null>                              | <null> |
| Node[24]{name:"EnterQueue"}                                                                          | Node[17]{name:"Main Support Queue"} | <null> |
| Node[27]{name:"RingAttempt"}                                                                         | <null>                              | <null> |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+

But why is agent null? I know for a fact that it exists. When I swap the two optional matches in the cypher query, it causes queue to be null and agent will instead be correct. I don't understand why.

Just to be clear I'm using neo4j-community-2.0.0-RC1.

Upvotes: 2

Views: 1761

Answers (1)

Eve Freeman
Eve Freeman

Reputation: 33175

You're using the same r identifier for the two optional match relationships, so it's already bound by the time you get to the second optional match, either as null, or as a relationship to a Queue. So, it will never match the Agent. Since you don't seem to care about the r, you can leave that out of the optional match.

match p = (call:Call)-[:NextEvent*]->(lastEvent:Event) where call.callid="123"
optional match (lastEvent)-[:Queue]->(queue:Queue) where lastEvent.name="EnterQueue"
optional match (lastEvent)-[:Agent]->(agent:User) where lastEvent.name="RingAttempt"
return lastEvent,queue,agent;

Upvotes: 3

Related Questions