给定模型
有一个模型,它们之间有类别和关系。 对于关系,如果它们绑定到特定的开始或结束类别,则可以指定它。
有四种关系:
代码:
MERGE (cat:ModelCategory {title:'Cat'})
MERGE (rel1:ModelRelation {title:'Outgoing'})
MERGE (rel2:ModelRelation {title:'Incoming'})
MERGE (rel3:ModelRelation {title:'Outgoing and Incoming'})
MERGE (rel4:ModelRelation {title:'Unbound'})
MERGE (rel1)-[:STARTS_AT]->(cat)
MERGE (rel2)-[:ENDS_AT]->(cat)
MERGE (rel3)-[:STARTS_AT]->(cat)
MERGE (rel3)-[:ENDS_AT]->(cat)
单次查询
如果选择“Cat”作为起始节点并想知道可以创建哪些关系和生成的结束节点,则可以使用单个查询:
// Relations with current source and a target
// Returns relation "Outgoing and Incoming"
MATCH (relation:ModelRelation)-[STARTS_AT]->(:ModelCategory{title:"Cat"}),
(relation)-[ENDS_AT]->(target)
RETURN DISTINCT relation, target
// Relations with current source and without target
// Returns relation "Outgoing"
MATCH (relation:ModelRelation)-[STARTS_AT]->(:ModelCategory{title:"Cat"})
WHERE NOT (relation)-[:ENDS_AT]->()
MATCH (allCategories:ModelCategory)
RETURN relation, allCategories as target
// Relations with target, without source
// Returns relation "Incoming"
MATCH (relation:ModelRelation)-[ENDS_AT]->(target)
WHERE NOT (relation)-[:STARTS_AT]->()
RETURN relation, target
// Relations without source or target
// Returns relation "Unbound"
MATCH (relation:ModelRelation)
WHERE NOT (relation)-[:STARTS_AT]->() AND NOT (relation)-[:ENDS_AT]->()
MATCH (allCategories:ModelCategory)
RETURN relation, allCategories as target
问题
合并四个查询的最佳方式是什么?
最简单的解决方案是在语句之间添加UNION。
也许最好首先获取标签ModelRelation和ModelCategory的所有节点,然后在子图上执行进一步的查询?
更新
更好的解决方案是在有或没有指定目标的情况下消除关系。 (导致一个类别或所有类别。)一个UNION仍然是必需的,两个子查询的第一部分是相同的。
// Relations which start at selected category or have no specified start
MATCH (relation:ModelRelation)
WHERE (relation)-[:STARTS_AT]->(:ModelCategory{title:"Cat"}) OR
NOT (relation)-[:STARTS_AT]->()
// Relations with specified targets
Match (relation)-[ENDS_AT]->(target)
RETURN relation, target
UNION
// Relations which start at selected category or have no specified start
MATCH (relation:ModelRelation)
WHERE (relation)-[:STARTS_AT]->(:ModelCategory{title:"Cat"}) OR
NOT (relation)-[:STARTS_AT]->()
// Relations without specified targets
MATCH (relation)
WHERE NOT (relation)-[:ENDS_AT]->()
MATCH (allCategories:ModelCategory)
RETURN relation, allCategories as target
答案 0 :(得分:1)
使用过滤器表示法和可变长度路径在一个查询中捕获所有这些,然后使用CASE
语句将空值替换为allCategories
。
MATCH (m:ModelCategory)
WITH COLLECT(m) AS allCategories
MATCH path = (:ModelCategory) <- [:STARTS_AT*0..1] - (:ModelRelation) - [:ENDS_AT*0..1] -> (:ModelCategory)
WITH CASE WHEN ANY(x in RELATIONSHIPS(path) WHERE TYPE(x) = 'STARTS_AT') THEN NODES(path)[0] ELSE allCategories END AS start,
[x IN NODES(path) WHERE x:ModelRelation][0] as relation,
CASE WHEN ANY(x IN RELATIONSHIPS(path) WHERE TYPE(x) = 'ENDS_AT') THEN LAST(NODES(path)) ELSE allCategories END AS end
RETURN start, relation, end
通常,您始终可以使用UNION
,COLLECT
和CASE
或0长度路径的正确组合替换OPTIONAL MATCH
个查询。通过扭曲是值得的,因为您可以在结果上运行聚合,而不是在每个查询中返回相同的列布局。
编辑:一个更简单的版本,每个关系返回一行。
MATCH (m:ModelCategory)
WITH COLLECT(m) AS allCategories
MATCH (relation:ModelRelation)
OPTIONAL MATCH (relation) - [:STARTS_AT] -> (start:ModelCategory)
OPTIONAL MATCH (relation) - [:ENDS_AT] -> (end:ModelCategory)
WITH COLLECT(start) AS starts, relation, COLLECT(end) AS ends, allCategories
RETURN
CASE starts WHEN [] THEN allCategories ELSE starts END AS relationStarts,
relation,
CASE ends WHEN [] THEN allCategories ELSE ends END AS relationEnds