How to access node objects in a collection of paths? (paths of two or more nodes)

Viewed 55

I have a graph where some nodes were created out of an error in the app. I want to delete those nodes (they represent a log), but I can't figure out how to loop thru the nodes.

I don't know how to access nodes in a collection of paths, and I need to do that in order to compare one node to another.

match (o:Order{id:123})
match (o)-[:STATUS_CHANGE*]->(l:Log)-[:STATUS]->(os:OrderStatus)

with collect((l:Log)-[:STATUS]->(os:OrderStatus)) as logs

I want to access each one of the nodes in the paths to perform a comparation. There are 5 or 6 of (l)-[:STATUS]->(os) normally for each Order.

How can I access the (l) and (os) nodes of each path, to perform the comparations between their properties?

For example, if I had this collection of paths in one of the Orders:

scenario1

(log1)-[:STATUS]->(os1)

(log2)-[:STATUS]->(os2)

(log3)-[:STATUS]->(os3)

(log4)-[:STATUS]->(os2) <-- This is the error

(log5)-[:STATUS]->(os4)

So, from the collection of paths above, I'd want to detach delete the (log4), because the (os2) node is lower than the previous one (os3), and should be greater.

And after that, I want to attach the (log3) to the (log5)


NOTE: Each one of the (os) nodes has an id that represents the "status", and go from 1 to 5. Also, the (log) nodes are ordered by the created datetime.


Any idea on how to do this? Thank you in advance guys!



EDIT

I didn't mention some other scenarios I had. This is one of them:

scenario 2

Based on @cybersam answer, I found out how to work it out.

I had to run 2 separated queries to make it work, but the principle is the same, and is as follows:

Create new relationships:

MATCH(o:Order)-[:STATUS_CHANGE*]->(l:Log)-[:STATUS]->(os:OrderStatus)
WHERE SIZE((o)-[:STATUS_CHANGE*]->()-[:STATUS]->(os)) >= 1
WITH o, os, COLLECT(l)[0] AS keep
WITH o, collect(keep) AS k
FOREACH(i IN range(0,size(k)-1)   | 
FOREACH(a IN [k[i]]               | 
FOREACH(b IN [k[i+1]]             | 
FOREACH(c IN CASE WHEN b IS NOT NULL THEN [1] END | MERGE (a)-[:STATUS_CHANGE]->(b) ))));

Delete exceeded nodes:

MATCH(o:Order)-[:STATUS_CHANGE*]->(l:Log)-[:STATUS]->(os:OrderStatus)
WHERE (os)<-[:STATUS]-()-[:STATUS_CHANGE*]->(l)-[:STATUS]->(os)
WITH o, os, COLLECT(l) AS exceed
UNWIND exceed AS del
detach delete del;

This queries worked on every scenario.

1 Answers

Assuming all your errors follow the same pattern (the unwanted Log nodes are always referencing an "older" OrderStatus), this may work for you:

MATCH (o:Order{id:123})-[:STATUS_CHANGE*]->(l:Log)-[:STATUS]->(os:OrderStatus)
WHERE SIZE(()-[:STATUS]->(os)) > 1
WITH os, COLLECT(l) AS logs
UNWIND logs[1..] AS unwanted
OPTIONAL MATCH (x)-[:STATUS_CHANGE]->(unwanted)-[:STATUS_CHANGE]->(y)
DETACH DELETE unwanted
FOREACH(ignored IN CASE WHEN x IS NOT NULL THEN [1] END | CREATE (x)-[:STATUS_CHANGE]->(y))

This query:

  • Finds (in order) all relevant OrderStatus nodes having multiple STATUS relationships.
  • Uses the aggregating function COLLECT to collect (in order) the Log nodes related to each of those OrderStatus nodes.
  • Uses UNWIND logs[1..] to get the individual unwanted Log nodes.
  • Uses OPTIONAL MATCH to get the 2 nodes that may need to be connected together, after the unwanted node is deleted.
  • Uses DETACH DELETE to deleted each unwanted node and its relationships.
  • Uses FOREACH to connect together the pair of nodes that might have been foiund by the OPTIONAL MATCH.
Related