Exclude paths with duplicated nodes - neo4j

In my flight modelization, I would like to search for path with 1 stop which is equivalent in the graph to have a 4 hops relationships from the source to the destination. When searching the path with :
match (s:Airport{airportName:'CAN'}),
(d:Airport{airportName:'ICN'})
with s,d
match p = (s)<-[*4]->(d)
return nodes(p), relationships(p)
But this also give me path with airport node that are visited twice, like this : airport node
So my question is, how to exclude paths which contains duplicated nodes ?
How to detect whether there is a duplicated node within a path ?
Thank you !

If you have access to APOC Procedures, you can try using apoc.algo.allSimplePaths(), which will not contain any loops back to a previously visited node in the path.
match (s:Airport{airportName:'CAN'}),
(d:Airport{airportName:'ICN'})
call apoc.algo.allSimplePaths(s, d, '', 4) yield path
return nodes(path), relationships(path)

Related

Neo4j -shortest path where intermediate nodes have a relationship [duplicate]

I have a graph database that consists of nodes (bus stations) with a property called “is_in_operation” which is set to “true” if the bus station is operational; otherwise it is set to “false”.
There is a relationship created between two nodes if a bus travels between the two stations.
I would like to find the path with the shortest number of stops between two nodes where all nodes in the path are operational.
There is an example in the database where there are 2 paths between 2 specified nodes. The “is_in_operation” property is set to ‘true’ for all nodes in both paths. When I run the following query, I get the correct answer
START d=node(1), e=node(5)
MATCH p = shortestPath( d-[*..15]->e ) where all (x in nodes(p) where x.is_in_operation='true')
RETURN p;
When I set the ‘is_in_operation’ property to ‘false’ for one of the intermediate nodes in the shortest path and rerun the query, I expect it to return the other path. However, I get no answer at all.
Is the query incorrect? If so, how should I specify the query?
The problem is that shortestPath can't take into account the where clause, so you're matching the shortest path, and then filtering it out with your where.
How about this one--it might not be as efficient as shortestPath, but it should return a result, if one exists:
START d=node(1), e=node(5)
MATCH p = d-[*..15]->e
where all (x in nodes(p) where x.is_in_operation='true')
RETURN p
order by len(p)
limit 1;

Neo4j Stop Graph Traversal when a particular node in a set is reached

I'm trying to find the shortest path from a set of source nodes to a set of target nodes in a dense graph. an example of connections is
(Node1)-[:ConnectsTo]->(Node2)-[...]->(NodeN)->(NodeM)
The challenge I have is that NodeN might be connected to NodeM wherein both nodes are in my list of targets. I would like to stop traversing the path when any node in my list of targets is reached.
Match (t:TestNode),(m:Node) where t.NODE_ID=m.NODE_ID
with m
MATCH path=shortestPath((m:Node)-[r:ConnectsTo*0..5]->(n:Node) )
where n.NODE_ID in
['123','283','21232','244464','35102','38591','53011']
RETURN last(nodes(path)),collect(extract(e IN nodes(path)| e.name))
An example of the output is:
[[DF2396, GMPP, DelHub], [DF2396, GMPP]]
where both GMPP and DelHub are Targets, and GMPP has a connection to DelHub, so I'd like to stop and return only the second path upto GMPP.
Please let me know if you'd like more details.
I believe I have the answer worked out. I added a 'not any' for the path that checked nodes and excluded paths where a node in the target set was not the last node in the path. I also improved the formatting of the return set with an unwind on the collection of paths.
Match (t:TestNode),(m:Node) where t.NODE_ID=m.NODE_ID
with m
MATCH path=shortestPath((m:Node)-[r:ConnectsTo*0..5]->(n:Node) )
where n.NODE_ID in
['123','283','21232','244464','35102','38591','53011']
and not any(x in nodes(path) where x.NODE_ID in ['123','283','21232','244464','35102','38591','53011']
and x<>last(nodes(path)))
with collect(extract(e IN nodes(path)| e.name)) as paths
unwind (paths) as sequences

Neo4j: Expres path cypher query result in terms of nodes

I have the following node structure Emp[e_id, e_name, e_bossid]. What is more I have a recursive query that exploit the database in recursive traversal on SELF relation e_bossid-[REPORTS_TO]->e_id
MATCH (e:Employee) WHERE NOT (e)-[:REPORTS_TO]->()
SET e:Root;
MATCH path = (b:Root)<-[:REPORTS_TO*]-(e:Employee)
RETURN path
limit 1000;
However the result is PATH. I would like to have result in form of NODES not the path. I tried to use the nodes(path), but it gives me an error:
org.codehaus.jackson.map.JsonMappingException: Reference node not available (through reference chain: java.util.ArrayList[0]->java.util.HashMap["rel"]->java.util.HashMap["nodes(path)"]->java.util.ArrayList[0]->org.neo4j.rest.graphdb.entity.RestNode["restApi"]->org.neo4j.rest.graphdb.RestAPIFacade["direct"]->org.neo4j.rest.graphdb.ExecutingRestAPI["referenceNode"])
When I query without nodes(path) it seems to return only paths.
How this should be done on the ground of cypher query?
I'm not sure why you would want to get all possible paths in your organizational hierarchy. Maybe what you want to get is a set of paths from the leaves of the tree to the root of the tree, and to return each unique set as a row of nodes.
MATCH (b:Employee)
WHERE NOT (b)-[:REPORTS_TO]->()
MATCH (l:Employee)
WHERE NOT (l)<-[:REPORTS_TO]-()
MATCH p = shortestPath((b)<-[:REPORTS_TO*]-(l))
RETURN nodes(p) as reports
As far as your error goes, that looks like a bug, although I don't know what version of Neo4j you are using. In all likelihood, your query won't complete because your Root employees are still a member of the Employee label. Which means that this pattern: MATCH path = (b:Root)<-[:REPORTS_TO*]-(e:Employee) matches the Root employees on each side of the variable length traversal.
Give my query a try and let me know what happens.

Neo4j Cypher - Terminating conditions when using variable level paths

I have a linked list that is modelled in a circular fashion like so:
(u:User)
-[:LINK]->(a:NODELINK {linkId: 'aa'})
-[:LINK]->(b:NODELINK {linkId: 'bb'})
-[:LINK]->(c:NODELINK {linkId: 'cc'})
-[:LINK]->(d:NODELINK {linkId: 'dd'})
-[:LINK]->(u)
When I query it starting at node (b:NODELINK {linkId: 'bb'}) I would like to match all nodes until I get to the end/start of the list. (The User node)
When I run the following query:
MATCH (u:USER)
WITH u
MATCH (nl:NODELINK)-[:LINK*]->(m)
WHERE nl.linkId = 'bb' AND m <> u
RETURN m
It returns me the following nodes
(3:NODELINK {linkId:'cc'})
(4:NODELINK {linkId:'dd'})
(1:NODELINK {linkId:'aa'})
(2:NODELINK {linkId:'bb'})
As you can see my query wraps around and starts returning nodes from the start of the list. I would like to terminate at the User node and only return the nodes before the end of the list
(3:NODELINK {linkId:'cc'})
(4:NODELINK {linkId:'dd'})
I have created a graph that demonstrates the issue here
How do I query so as to start at the node link of interest and returns all nodes before it reaches the User node?
Your WHERE clause limits the first and last node in the path, but not the intermediate ones, so yes, the query can match paths that include the user node.
Instead of matching many paths and returning only the end nodes, try matching one path from the 'cc' node to the user node, and return all nodes in that path (except the last one if you don't want the user node).
MATCH path=(nl:NODELINK {linkId:'cc'})-[:LINK*]->(u:USER)
RETURN nodes(path)
or
RETURN nodes(path)[..-1]
if you want to return all the nodes except the last one.
Try below query. I think you should bring the NODELINK where you want to begin traversing in the first MATCH clause as it will pin point your graph where to start instead of just matching user node on USER label.
MATCH (nl:NODELINK)
WHERE nl.linkId = 'aa'
WITH nl
MATCH p=(nl)-[:LINK*1..]->(m:USER)
RETURN filter(t IN nodes(p)
WHERE t <> nl) AS nodes

How to verify that some nodes exists in a path using cypher

I want to get all paths between two nodes so that at least one node from a list of nodes exists in those paths.
how can I do this using cypher ?
Assuming you have provided your list of nodes as a cypher collection, would this do the job?
MATCH path=(start)-[r:*1..100]-(end)
WHERE ANY(node_on_path in NODES(path)
WHERE node_on_path IN node_collection)
You may also try using a list of values against which the nodes on the path are checked, something like
MATCH path=(start)-[r:1..100]-(end)
WHERE ANY(node_on_path in NODES(path)
WHERE node_on_path.some_property IN list_of_acceptable_values)

Resources