Reputation: 273
Take the following pattern which starts with a node labelled “Conversation” and has one long chain of [:RESPONSE] relationships.
There are many nodes in this pattern, but we only care about 2 of them: (Answer) and (Element). And there is only one relationship we care about: [:RESPONSE]
(Conversation) <-[:RESPONSE]-(unimportant_node)<-[:RESPONSE]
..()..()..()..(Answer)<-()..()..(Element)..().().()..()..()..
(Answer)…()..(Element)<—()..()..(Answer)-..()-..(Element)<-..().()
What I want is to find ALL the (Answers), each with its associated (Element).
The variable part: the number of nodes between (Conversation) and (Answer), and also between (Answer) and (Element) is variable.
The invariable part: After each (Answer) there is an (Element) node, which is basically associated to that (Answer). Then, at some point, there is another (Answer), which also has an associated (Element).
What I'm doing: Because I want to retrieve all the (Answers), I use (c:Conversation)<-[:RESPONSE*]–(a:Answer).
Then, because I don’t know how many nodes are between (Answer) and its associated (Element), I use again [:RESPONSE*].
So, my query looks like this:
match (c:Conversation) <- [:RESPONSE*] - (a:Answer) <-[:RESPONSE*]-(e:Element)
this brings ALL the (Elements) following each (Answer), which is not good, because I’m only interested in the FIRST (Element) following each (Answer).
I did manage to find this solution:
match (c:Conversation) <- [:RESPONSE*] - (a:Answer) <- [:RESPONSE*] - (e:Element)
with c,a,head(collect(e)) as first_e //could also use: collect(e)[0] as first_e
...code continues...
However, I’m looking for an alternative solution which would simply just find the first (Element) after each (Answer) and then stop, thus making Cypher work a lot less.
Playing with this, I’ve noticed that it’s quite easy to bring only the first (Answer) if I want to. (In my case, however, I want all of them, so I’m not doing it).
match (c:Conversation) <- [:RESPONSE*] - (a:Answer) <- [:RESPONSE*]-(e:Element)
where not( (:Answer)<- [:RESPONSE]-(a) )
I figured there must be an easy way to apply this technique to bring just the first (Element) after each (Answer), so I’ve tried:
match (c:Conversation) <- [:RESPONSE*]-(a:Answer)
with c,a
match (a) <-[:RESPONSE*]-(e:Element)
where not( (:Answer)<- [:RESPONSE]-(a) )
Unfortunately, this logic is not applied in a for_each (Answer) scope, but rather it’s applied for the whole query. As such, this will only bring 1 row of results:
conversation | the_very_last_Answer | the_very_last_element
I’ve also tried putting the MATCH in a FOREACH, but I get a SyntaxError.
Upvotes: 1
Views: 65
Reputation: 16355
You can install APOC procedures and do it using apoc.cypher.run
procedure. Something like this:
MATCH (c:Conversation)<-[:RESPONSE*]-(a:Answer)
CALL apoc.cypher.run('
WITH {a} AS a
MATCH (a)-[:RESPONSE*]->(e:Element)
RETURN e LIMIT 1',
{a:a}) YIELD value
RETURN c, value.e
With apoc.cypher.run
you can execute a subquery with LIMIT
(1, in this case) per row.
Upvotes: 1