I always start from brown or purple(with digit) node and I'd like find all the nearest pink node.
The count of nearest node isn't known. I tried to use apoc.path.expandConfig but I have to specify a limit or this call will return all of nodes with certain label which are connected in any hops
match(n{id:0}) where n:Brown or n:Purple
match path=(n)-[*]-(m:Pink)
with m, length(path) as len
with collect({node:m, length:len}) as data, min(len) as min_len
with [i in data where i.length = min_len] as pink_nodes
unwind pink_nodes as node
return node
Two nodes meet the requirements of query. I would like to find the closest pink node for each of this node (distance isn't the same). This is my query CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk') YIELD node match path=(node)-[*]-(m:reference) with m, length(path) as len with collect({node:m, length:len}) as data, min(len) as min_len with [i in data where i.length = min_len] as pink_nodes unwind pink_nodes as node return node
I modified the query to work with multiple starting nodes. The query below will find the closest ‘reference’ nodes for each starting node. A list of the closest node is returned for each starting node, and the minimum length. A collection is returned in case there are multiple reference nodes that have the same minimum distance.
The lists contain the entire node. You can extract just the information you need for these nodes by adding a transformation to the list comprehension.
CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk') YIELD node
match path=(node)-[*]-(m:reference)
with node, m, length(path) as len
with node, collect({node:m, length:len}) as data, min(len) as min_len
return node, [i in data where i.length = min_len | i.node] as closest_nodes, min_len
The answer of @glilienfield is good but can take a long time to run in a very dense graph. You should try shortestPath() if it meets your need:
CALL db.index.fulltext.queryNodes('textIndex', 'Gdansk')
YIELD node
MATCH path = shortestPath((node)-[*]-(m:reference))
WITH node, m, length(path) AS len
WITH node, collect({node:m, length:len}) AS data, min(len) AS min_len
WITH node, [i IN data WHERE i.length = min_len] AS closest_nodes, min_len
@cobra, doesn’t the neo4j shortestPath method require knowing the start and end nodes? The end node is unknown in this case?
The approach is not efficient because it exhaustively find all paths, then filters based on length to return only the ones that are the shortest. It would be best to perform a breadth- first search looking for nodes of the desired label, then stop searching when nodes with the label are found. This isn’t achievable in cypher, but requires a traversal algorithm.
You can do a MATCH to get all nodes you want as end nodes and use them to set the parameter terminatorNodes for the apoc.path.expandConfig() procedure.
CALL db.index.fulltext.queryNodes('textIndex', 'x') YIELD node MATCH (n:reference) CALL apoc.path.expandConfig(node,{terminatorNodes:[n], bfs:TRUE}) yield path as p WITH n, length(p) AS len WITH collect({node:n, length:len}) AS data, min(len) AS minLen WITH [i IN data WHERE i.length = minLen] AS closest_nodes UNWIND closest_nodes AS ids WITH collect(ids.node) AS x return x