首页 > 解决方案 > Neo4j - Cypher - 包含父母和孩子的图片库系统

问题描述

我是具有 mysql 背景的 Neo4j 新手,我正在尝试将旧的 mysql 图像库系统转换为 Neo4j 图形数据库,我提供的架构如下图所示:

neo4j 图

_ 有两个关系类型的用户节点:

_ 具有两种关系类型的帖子节点:

_ 最后的图像节点。

这是一个简化版本,实际上每个帖子(父母和孩子)都可以有链接或视频而不是图像,并且可以被用户评论或喜欢。

为了从图中获取我需要的所有数据,我使用了这个密码查询:

MATCH (p:Post)<-[:POSTED]-(u:User) WHERE NOT (p)<-[:HAS_CHILD]-(:Post)
MATCH (u)-[:HAS_AVATAR]->(ua:Image)
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post)
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image)
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image)
RETURN
[p._id, [u.username, ua._id], i._id, c._id, ci._id] as post

它最终得到这样的结果:

在此处输入图像描述

再次,我保持这个查询简单,为了清楚起见,每个图像都有一个 id、一个宽度和一个高度,每个子帖子可以有与其父不同的用户,每个帖子都有自己的评论和来自不同的喜欢用户真正的结果是远远大于这个。

现在我必须处理很多lodash/union,以摆脱所有重复的结果(帖子ID,用户名......)

我的问题是,我做得对吗?有更好的方法吗?我实际上正在阅读MERGE并尝试实施它。

所以我指的是你们和你们的专业知识,特别是如果它可以在密码查询中获取所有联合函数。

谢谢。

标签: databasegraphneo4jcypher

解决方案


从评论来看,您似乎想使用聚合将结果收集在一起,并最大限度地减少结果中的行数和元素重复。

从您的查询来看,您可能已经尝试通过输出列表来执行此操作。请记住,将一些结果放入列表(仅更改每行结果的结构)与使用或其他进行聚合的方法之间存在差异collect(),因为它从多行获取结果并将它们收集到一个行(每个分组键),因此最终总行数更少。

这是您的查询,其中包含为每个父帖子收集子帖子的更改:

MATCH (p:Post)<-[:POSTED]-(u:User) 
WHERE NOT (p)<-[:HAS_CHILD]-() 
// the above uses the degree of those relationships on the node, more efficient
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post) // potentially multiple children
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image) // assume at most 1 image per child post
WITH p, u, collect(c {._id, image:ci._id}) as children
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image) // assume at most 1 image per post
WITH p, u, children, i
MATCH (u)-[:HAS_AVATAR]->(ua:Image) // assume at most 1 avatar per user
RETURN p {._id, image:i._id, children} as post, u {.username, avatar:ua._id} as user

这使用地图投影从地图中投影出属性(或者在这种情况下,从节点中投影出属性)并将我们自己的属性从其他匹配元素添加到地图中。

或者,如果你想做类似的事情,但除了收集每个用户的帖子,你可以这样做:

MATCH (p:Post)<-[:POSTED]-(u:User) 
WHERE NOT (p)<-[:HAS_CHILD]-() 
// the above uses the degree of those relationships on the node, more efficient
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post) // potentially multiple children
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image) // assume at most 1 image per child post
WITH u, p, collect(c {._id, image:ci._id}) as children
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image) // assume at most 1 image per post
WITH u, collect(p {._id, image:i._id, children}) as posts
MATCH (u)-[:HAS_AVATAR]->(ua:Image) // assume at most 1 avatar per user
RETURN u {.username, avatar:ua._id} as user, posts

推荐阅读