Neo4j 图数据库入门(二):一篇搞定 Cypher 增删改查——在电影社交网络里从 0 建到删

2211 字
11 分钟
Neo4j 图数据库入门(二):一篇搞定 Cypher 增删改查——在电影社交网络里从 0 建到删

本系列导航

  • 第一篇:图数据库概念——为什么是图、四大核心概念、环境搭建
  • 第二篇(本篇):Cypher 增删改查全流程
  • 第三篇:MERGE 防重、聚合分析、索引约束与完整实战

所有示例仍基于第一篇定义的「电影社交网络」场景。请在 Neo4j Browser(http://localhost:7474)中按顺序执行本文代码,你会亲眼看着一张空图长成完整的电影社交网络。

20/80 承诺:掌握本篇的 CREATE / MATCH / SET / DELETE,就能覆盖日常 80% 的数据操作。


0. 热身:从一张空图开始#

无论你的库里有什么旧数据,先执行这条清空(顺便认识本篇最后一位主角 DELETE):

MATCH (n) DETACH DELETE n;

读法:“匹配所有节点,连同它们的关系一起删掉”。现在,图是空的。


1. 增(CREATE)#

1.1 创建节点#

CREATE (p:Person {name: '张三', age: 30, gender: '男'})
RETURN p;

拆解语法:

  • (p:Person ...):一个节点,变量名 p(仅当前语句有效),标签 Person
  • {...}:节点属性,键值对
  • RETURN p:把创建的节点返回到画面上(可省略)

继续把电影和公司也建出来:

CREATE (m:Movie {title: '流浪地球', year: 2019, rating: 7.9})
RETURN m;
CREATE (c:Company {name: '中影股份', founded: 1999})
RETURN c;

1.2 批量创建#

一条语句创建多个节点,逗号分隔:

CREATE
(p1:Person {name: '李四', age: 28}),
(p2:Person {name: '王五', age: 35}),
(p3:Person {name: '赵六', age: 26}),
(m1:Movie {title: '三体', year: 2023, rating: 8.5}),
(m2:Movie {title: '满江红', year: 2023, rating: 7.0}),
(c1:Company {name: '光线传媒', founded: 1998});

现在,第一篇那张”世界观”图里的 9 个节点都在了。可以跑 MATCH (n) RETURN n; 看一眼——一堆孤立的点,下一步让他们连接起来。

1.3 创建关系:先 MATCH,再 CREATE#

关系连接的是已经存在的两个节点,所以套路固定为”先 MATCH 到它们,再 CREATE 关系”:

MATCH (a:Person {name: '张三'}), (b:Person {name: '李四'})
CREATE (a)-[:KNOWS {since: 2018}]->(b)
RETURN a, b;

用同样的套路,把好友链和合作关系统统建好:

// 好友链:李四 → 王五 → 赵六,以及张三 → 王五
MATCH (a:Person {name: '李四'}), (b:Person {name: '王五'})
CREATE (a)-[:KNOWS {since: 2020}]->(b);
MATCH (a:Person {name: '王五'}), (b:Person {name: '赵六'})
CREATE (a)-[:KNOWS {since: 2021}]->(b);
MATCH (a:Person {name: '张三'}), (b:Person {name: '王五'})
CREATE (a)-[:KNOWS {since: 2019}]->(b);
// 张三 出演 流浪地球,关系上带角色属性
MATCH (p:Person {name: '张三'}), (m:Movie {title: '流浪地球'})
CREATE (p)-[:ACTED_IN {role: '工程师', year: 2019}]->(m);
// 李四 导演 流浪地球
MATCH (p:Person {name: '李四'}), (m:Movie {title: '流浪地球'})
CREATE (p)-[:DIRECTED {year: 2019}]->(m);
// 赵六 出演 三体
MATCH (p:Person {name: '赵六'}), (m:Movie {title: '三体'})
CREATE (p)-[:ACTED_IN {role: '科学家', year: 2023}]->(m);
// 王五 就职于 中影股份
MATCH (p:Person {name: '王五'}), (c:Company {name: '中影股份'})
CREATE (p)-[:WORKS_AT {position: '制片人', since: 2015}]->(c);
// 张三 评价 满江红:属性挂在关系上
MATCH (p:Person {name: '张三'}), (m:Movie {title: '满江红'})
CREATE (p)-[:REVIEWED {score: 8, comment: '剧情紧凑'}]->(m);

再执行 MATCH (n) RETURN n;——第一篇的数据模型全景图,此刻完整呈现在你的画布上。

1.4 一步到位:建节点的同时建关系#

新节点和关系可以一条语句搞定:

MATCH (p:Person {name: '赵六'})
CREATE (p)-[:ACTED_IN {role: '配角', year: 2023}]->(m:Movie {title: '孤注一掷', year: 2023, rating: 6.9})
RETURN p, m;

注意:CREATE 每次都会新建,如果这句话跑两遍,会出现两部《孤注一掷》。怎么防重?第三篇的 MERGE 就是干这个的。


2. 查(MATCH + RETURN)#

MATCH 画模式,RETURN 取结果——第一篇预告过的”画图思维”,现在正式上手。

2.1 基础查询#

// 所有人物
MATCH (p:Person) RETURN p;
// 只取电影的部分属性(返回表格而不是节点)
MATCH (m:Movie) RETURN m.title, m.year, m.rating;
// 精确匹配一个人物
MATCH (p:Person {name: '张三'}) RETURN p;

2.2 WHERE 条件过滤#

{} 内联属性适合精确匹配,灵活条件交给 WHERE

// 年龄大于 27 的人
MATCH (p:Person)
WHERE p.age > 27
RETURN p.name, p.age;
// 组合条件:年龄大于 25 且姓张
MATCH (p:Person)
WHERE p.age > 25 AND p.name STARTS WITH '张'
RETURN p.name, p.age;
// 模糊匹配:名字含"三"
MATCH (p:Person)
WHERE p.name CONTAINS '三'
RETURN p.name;
// IN 列表:2019 或 2023 年的电影
MATCH (m:Movie)
WHERE m.year IN [2019, 2023]
RETURN m.title, m.year;

2.3 关系查询:顺着箭头找#

// 张三认识谁?
MATCH (:Person {name: '张三'})-[:KNOWS]->(friend:Person)
RETURN friend.name;
// 谁导演了流浪地球?(箭头方向反过来)
MATCH (director:Person)-[:DIRECTED]->(:Movie {title: '流浪地球'})
RETURN director.name;
// 张三出演的电影,以及关系上的角色属性
MATCH (:Person {name: '张三'})-[r:ACTED_IN]->(m:Movie)
RETURN m.title, r.role, r.year;

第三条示例是图模型独有的便利:ACTED_IN 关系自带 role 属性,直接取用,不需要中间表。

2.4 多跳路径查询——图数据库的高光时刻#

还记得第一篇那个”五层 JOIN”的问题吗?现在正面回答它:

// 张三的朋友的朋友(2 跳)
MATCH (:Person {name: '张三'})-[:KNOWS]->()-[:KNOWS]->(fof:Person)
RETURN DISTINCT fof.name;

DISTINCT 去重很重要——张三认识王五(1 跳直达),王五也是他的”朋友的朋友”,会被查出来两次。

可变长度路径*1..3 表示沿 KNOWS 关系走 1 到 3 步,一行代码就是”张三的 1~3 度人脉”:

MATCH (:Person {name: '张三'})-[:KNOWS*1..3]->(contact:Person)
RETURN DISTINCT contact.name;

再两个进阶玩法:

// 张三到赵六之间的所有路径
MATCH path = (:Person {name: '张三'})-[:KNOWS*]->(:Person {name: '赵六'})
RETURN path;
// 最短路径(跨关系类型,* 不指定类型即任意关系)
MATCH path = shortestPath(
(:Person {name: '张三'})-[*]-(:Person {name: '赵六'})
)
RETURN path;

在 SQL 里,这三条每条都是多层嵌套子查询;在 Cypher 里,它们只是”把箭头多画几下”。

2.5 双向查询:不指定方向#

认识关系一般视为无向,把 -> 改成 - 即可:

// 与张三有 KNOWS 关系的所有人(不区分谁认识谁)
MATCH (:Person {name: '张三'})-[:KNOWS]-(other:Person)
RETURN other.name;

3. 改(SET 与 REMOVE)#

3.1 SET:修改属性#

// 改一个属性
MATCH (p:Person {name: '张三'})
SET p.age = 31
RETURN p;
// 改多个属性
MATCH (p:Person {name: '张三'})
SET p.age = 31, p.email = 'zhangsan@example.com'
RETURN p;
// += 合并属性:只新增/覆盖列出的键,其余保留
MATCH (p:Person {name: '张三'})
SET p += {city: '北京', hobby: '跑步'}
RETURN p;

SET p = {...}整体替换所有属性,SET p += {...}合并。日常批量补字段用 += 更安全。

3.2 SET / REMOVE:给节点增删标签#

标签可以动态增删(这在关系型数据库里相当于”把一行挪到另一张表”,图里只是一次标记变更):

// 给张三加一个 Actor 标签
MATCH (p:Person {name: '张三'})
SET p:Actor
RETURN p;
// 再删掉
MATCH (p:Person {name: '张三'})
REMOVE p:Actor
RETURN p;

3.3 REMOVE:删除属性#

MATCH (p:Person {name: '张三'})
REMOVE p.email
RETURN p;

4. 删(DELETE)#

4.1 删除关系#

// 删掉张三和李四之间的 KNOWS 关系
MATCH (:Person {name: '张三'})-[r:KNOWS]->(:Person {name: '李四'})
DELETE r;

4.2 删除节点:DETACH DELETE(新手必踩的坑)#

先试试点删赵六:

MATCH (p:Person {name: '赵六'})
DELETE p;

会报错 Neo.ClientError.Schema.ConstraintValidationFailed 之类的错误——因为赵六身上还连着关系(认识王五、出演三体)。Neo4j 不允许删除仍被关系引用的节点,这其实是保护机制。

正确姿势是 DETACH DELETE:先摘掉所有关系,再删节点:

MATCH (p:Person {name: '赵六'})
DETACH DELETE p;

4.3 清空整个数据库#

// 危险操作!删除所有节点和关系
MATCH (n) DETACH DELETE n;

清空后别慌——第三篇的完整实战脚本会把整张电影社交网络一键重建回来。


5. CRUD 速查表#

操作语法骨架记忆点
建节点CREATE (p:Label {props})直接创建,可能重复
建关系MATCH (a),(b) CREATE (a)-[:TYPE]->(b)先 MATCH 到节点再连
MATCH 模式 WHERE 条件 RETURN 结果画模式 → 过滤 → 取值
多跳-[:TYPE*1..3]->星号 + 跳数范围
改属性SET p.k = v / SET p += {...}= 替换单值,+= 合并
增删标签SET p:X / REMOVE p:X标签动态可变
删属性REMOVE p.k属性和标签都用 REMOVE
删关系DELETE r只删关系不影响节点
删节点DETACH DELETE p有关系的节点必须 DETACH

小结与预告#

到这里,你已经在电影社交网络里完整走了一遍增删改查:

  • CREATE 节点与关系,关系的套路是”先 MATCH 再 CREATE”
  • MATCH 画模式 + WHERE 过滤,多跳路径是图数据库的杀手锏
  • SET 改属性/标签,REMOVE 删属性/标签
  • DELETE 删关系,DETACH DELETE 删节点,清库一句话

但还有两个隐患没有解决:CREATE 会产生重复数据,查询多了怎么更快、怎么统计?下一篇《Neo4j 图数据库入门(三):从会写到写好——MERGE 防重、聚合分析、索引约束与完整实战》,我们把”能用”升级为”用好”,并用一段完整脚本重建全图,给整个系列收官。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Neo4j 图数据库入门(二):一篇搞定 Cypher 增删改查——在电影社交网络里从 0 建到删
https://kianzhao.site/posts/Neo4j_Senior/
作者
Kian Zhao
发布于
2026-09-05
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Kian Zhao
Hello, I'm Kian Zhao.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
32
分类
8
标签
24
总字数
48,238
运行时长
0
最后活动
0 天前

目录