Question

I have a Cypher query that returns closed circle results like

a-b-t-y-a
b-t-y-w-b 

and so on ...

From time to time I get results like

a-b-c-b-e-f-a
c-e-r-e-f-g-c
c-e-r-c-d-a-c

that I do not need

In this two results I have b-in first and e in second visited twice , and c is shown also not only at the start and at the end as it should be but in the middle also . .

How to avoid getting results where I get same nodes in inner part of results or getting the start and end node inside also .The same node at the start and at the end of result is fine .

My current cypher query is :

start n=node(*) match p=n-[r:OWES*1..200]->n   
where  HAS(n.taxnumber) 
return extract(s in `relationships(p) : s.amount), extract(t in nodes(p) : ID(t)), length(p); 

I am getting all nodes that have taxnumber property and connected with relation OWES , all up to level of 200 .

Was it helpful?

Solution

If you can't use CASE you could try this. I tested it on a 1.8.3 server and it runs ok. I was not able to get it working with reduce. I got several different unexpected errors, including 'unclosed parenthesis' and type comparison problems, this was the only query that I got to work. I also ran it on a 2.0 server and it finished in ~39s what Michael's query with case and reduce did in ~23s on a mockup data set.

START n=node(*) 
MATCH p=n-[r:OWES*1..200]->n 
WHERE HAS(n.taxnumber) AND 
    ALL(x IN tail(nodes(p)) WHERE SINGLE(y IN tail(nodes(p)) WHERE x=y))        
RETURN EXTRACT(s IN relationships(p) : s.amount), EXTRACT(t IN nodes(p) : ID(t)), length(p)

OTHER TIPS

Can't you check for non-duplicates in the path? Right now cypher misses a uniq function that would make this simple, here is a workaround.

This is for neo4j 2.0, as 1.9 doesn't have case when there it might be more involved, probably using filter

start n=node(*) 
match p=n-[r:OWES*1..200]->n   
where HAS(n.taxnumber) AND 
  reduce(a=tail(nodes(p)), x in tail(nodes(p)) |
      case when a IS NOT null OR x in tail(a) then null else tail(a) end) IS NOT NULL
return extract(s in relationships(p) | s.amount), extract(t in nodes(p) | ID(t)), length(p); 

for 1.9 you might use an expression like this to find duplicates:

WITH [1,2,3] AS coll

reduce(a=false, x IN coll : a OR length(filter(y IN coll : x = y))> 1)

It works like this:

  • uses tail(nodes(path)) b/c you have the same start and end node which would always be a duplicate
  • it reduces over all elements of the collection and when it doesn't find the element again in the rest of the collection it returns the rest of the collection and repeats
  • otherwise it returns null and shortcuts
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top