我正在为一个简单的文件系统建模,包含文件夹和文件。
(:Folder)<-[:IS_IN *]-(:Folder)<-[:IS_IN]-(:File)
用户可以给我任意路径,
/foo/bar/baz.txt
。在这种情况下,图表看起来像:
(:Folder {Name: '/'})<-[:IS_IN]-(:Folder {Name: 'bar'})<-[:IS_IN]-(:File {Name: 'baz.txt'})
在不知道用户将提供多长路径的情况下,是否有一种好的方法来查询给定路径是否在图中表示?如果我将路径拆分为文件夹名称的有序列表,我是否可以编写一个查询,当且仅当它们以与列表相同的顺序存在时返回节点?
天真地我可以用每个节点动态生成一个查询,但我宁愿不生成动态查询。
假设你传递了这个
$path
参数,并且路径中的最后一个元素是一个文件:
"/foo/bar/baz.txt"
假设你的数据是这样的:
(:Folder {Name: '/'})<-[:IS_IN]-
(:Folder {Name: 'foo'})<-[:IS_IN]-
(:Folder {Name: 'bar'})<-[:IS_IN]-
(:File {Name: 'baz.txt'})
这应该有效:
WITH SPLIT($path, '/') AS p
WITH REVERSE(CASE WHEN p[0] = '' THEN ['/']+p[1..] ELSE p END) AS names
OPTIONAL MATCH (file:File {Name: names[0]})
RETURN REDUCE(s=file, n IN names[1..] |
CASE WHEN s IS NOT NULL THEN [(s)-[:IS_IN]->(f1 {Name: n})|f1][0] END
) IS NOT NULL AS found
查询会返回是否找到
$path
中的路径
它将 $path 字符串分解为文件夹和文件名数组,将其反转,然后可选地匹配文件节点。我们使用 OPTIONAL MATCH,以便查询始终返回一个值,即使未找到文件。然后我们使用 REDUCE 函数循环遍历路径中的剩余文件夹,以验证每个需要的关系是否存在。我们使用 pattern comprehension 在循环中执行匹配。