如何编写Cypher查询按关系类型动态分组关联节点?
问题描述
数据模型
(PersonA)-[:KNOWS]->(PersonB) (PersonA)-[:KNOWS]->(PersonC) (PersonA)-[:IS_FRIENDS_WITH]->(PersonD) (PersonA)-[:LIKES]->(PersonE)
需求
编写Cypher查询返回PersonA,以及按关系类型分组的关联人员列表,输出格式如下:
{ "id": "PersonA", "knows": [ {"id": "PersonB"}, {"id": "PersonC"} ], "is_friends_with": [ {"id": "PersonD"} ], "likes": [ {"id": "PersonE"} ] }
核心要求:不能硬编码关系类型,支持任意关系类型。
遇到的问题
尝试使用apoc.map.groupMulti,但该函数仅支持按节点属性分组,无法按关系类型分组,寻求解决办法。
解决方案
可以结合Cypher原生函数和APOC工具函数实现动态分组,以下是两种可行写法:
写法一:COLLECT + apoc.map.fromPairs
MATCH (a:Person {id: 'PersonA'})-[r]->(b) WITH a, LOWER(TYPE(r)) AS relType, COLLECT({id: b.id}) AS people WITH a, COLLECT([relType, people]) AS relGroups RETURN apoc.map.fromPairs(COLLECT(['id', a.id]) + relGroups) AS result
代码说明
- 匹配目标节点
PersonA及其所有向外的关系、关联节点 - 将关系类型转为小写(和示例输出格式对齐),收集同一关系类型下的所有关联节点信息
- 把每个关系类型与对应人员列表打包成键值对数组,再加入
PersonA的ID键值对 - 用
apoc.map.fromPairs将键值对数组转换为最终的JSON格式对象
如果不需要关系类型小写,直接去掉LOWER()函数即可。
写法二:apoc.agg.groupBy(更简洁)
MATCH (a:Person {id: 'PersonA'})-[r]->(b) WITH a, apoc.agg.groupBy(TYPE(r), {id: b.id}) AS relGroups RETURN apoc.map.merge({id: a.id}, relGroups) AS result
代码说明
apoc.agg.groupBy可直接按关系类型(TYPE(r))分组,自动收集对应关系下的关联节点信息- 最后用
apoc.map.merge将PersonA的ID和分组结果合并成符合要求的对象
内容的提问来源于stack exchange,提问作者oculardexterity
相关产品推荐
相关产品推荐

