1. 什么是CRUD操作 #
在数据库操作中,CRUD是最基本的四个操作:
- Create(创建):创建新的数据
- Read(读取):查询和读取数据
- Update(更新):修改现有数据
- Delete(删除):删除数据
在图数据库中,CRUD操作有一些特殊之处:
- 创建:可以创建节点和关系,以及它们的属性
- 更新:可以更新节点和关系的属性,也可以添加或删除标签
- 删除:可以删除节点、关系或属性,但需要注意节点和关系之间的依赖关系
2. 创建数据(CREATE) #
创建数据是数据库操作的第一步。在Cypher中,使用CREATE关键字来创建节点和关系。
2.1 CREATE命令的基本语法 #
CREATE命令用于创建新的节点和关系。它的基本语法是:
- 创建节点:
CREATE (变量名:标签 {属性}) - 创建关系:
CREATE (节点1)-[:关系类型 {属性}]->(节点2)
2.2 创建节点 #
创建节点是最基本的操作。可以创建带标签和属性的节点。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建一个简单的节点
CREATE (p:Person {name: "张三"})
// 查询创建的节点
MATCH (p:Person)
RETURN p
// 创建带标签的节点
CREATE (c:Company {name: "科技公司"})
// 查询所有节点
MATCH (n)
RETURN n2.3 创建带多个属性的节点 #
节点可以有多个属性,用于存储更多信息。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建带多个属性的节点
CREATE (p:Person {
name: "张三",
age: 30,
city: "北京",
email: "zhangsan@example.com"
})
// 查询节点及其属性
MATCH (p:Person)
RETURN p.name, p.age, p.city, p.email
// 创建多个带属性的节点
CREATE (p1:Person {name: "李四", age: 25, city: "上海"}),
(p2:Person {name: "王五", age: 35, city: "广州"})
// 查询所有人员
MATCH (p:Person)
RETURN p.name, p.age, p.city2.4 创建关系 #
关系连接两个节点,也可以有自己的属性。
// 清空数据库
MATCH (n) DETACH DELETE n
// 先创建节点
CREATE (p1:Person {name: "张三"}),
(p2:Person {name: "李四"}),
(c1:Company {name: "科技公司"})
// 查询插入后的节点(还没有关系)
MATCH (n)
RETURN n
// 查询初始关系(应该为空)
MATCH (p:Person)-[r]->(target)
RETURN count(r) AS initial_relationship_count
// 创建关系(无属性)
MATCH (p1:Person {name: "张三"}),
(p2:Person {name: "李四"})
CREATE (p1)-[:IS_FRIENDS_WITH]->(p2)
// 查询创建关系后的状态
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 创建带属性的关系
MATCH (p1:Person {name: "张三"}),
(c1:Company {name: "科技公司"})
CREATE (p1)-[:WORKS_FOR {since: 2020, role: "工程师"}]->(c1)
// 查询所有节点和关系
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name, r
// 查询工作关系及其属性
MATCH (p:Person)-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.since, r.role, c.name2.5 创建复杂图结构 #
可以一次性创建多个节点和关系,构建复杂的图结构。
// 清空数据库
MATCH (n) DETACH DELETE n
// 一次性创建多个节点和关系
CREATE (p1:Person {name: "张三", age: 30}),
(p2:Person {name: "李四", age: 25}),
(p3:Person {name: "王五", age: 35}),
(c1:Company {name: "科技公司"}),
(c2:Company {name: "互联网公司"}),
(p1)-[:IS_FRIENDS_WITH]->(p2),
(p2)-[:IS_FRIENDS_WITH]->(p3),
(p1)-[:WORKS_FOR {since: 2020}]->(c1),
(p2)-[:WORKS_FOR {since: 2021}]->(c2),
(p3)-[:WORKS_FOR {since: 2019}]->(c1)
// 查询完整的图结构
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 查询朋友关系网络
MATCH (p1:Person)-[:IS_FRIENDS_WITH]->(p2:Person)
RETURN p1.name, p2.name
// 查询工作关系
MATCH (p:Person)-[r:WORKS_FOR]->(c:Company)
RETURN p.name, c.name, r.since3. 更新数据(SET) #
更新数据是修改现有节点或关系属性的操作。在Cypher中,使用SET关键字来更新属性。
3.1 前置知识:SET命令 #
SET命令用于设置或更新节点和关系的属性。它的基本语法是:
- 更新节点属性:
SET 节点变量.属性名 = 值 - 更新关系属性:
SET 关系变量.属性名 = 值
3.2 更新节点属性 #
可以更新节点的单个或多个属性。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三", age: 30})
// 查询插入后的初始数据
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age
// 更新单个属性
MATCH (p:Person {name: "张三"})
SET p.age = 31
RETURN p
// 查询更新后的节点
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age
// 更新另一个属性
MATCH (p:Person {name: "张三"})
SET p.city = "北京"
RETURN p.name, p.age, p.city
// 查询最终状态
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.city3.3 更新多个属性 #
可以一次更新多个属性,用逗号分隔。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三", age: 30})
// 查询插入后的初始数据
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age
// 一次更新多个属性
MATCH (p:Person {name: "张三"})
SET p.age = 31, p.city = "北京", p.email = "zhangsan@example.com"
RETURN p
// 查询更新后的所有属性
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.city, p.email
// 创建更多测试数据
CREATE (p2:Person {name: "李四", age: 25})
// 更新多个节点的属性
MATCH (p:Person)
SET p.updated = true, p.update_time = timestamp()
RETURN p.name, p.updated, p.update_time3.4 使用表达式更新属性 #
可以使用表达式来计算新的属性值。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三", age: 30, salary: 10000})
// 查询插入后的初始数据
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.salary
// 使用表达式更新属性(年龄加1)
MATCH (p:Person {name: "张三"})
SET p.age = p.age + 1
RETURN p.name, p.age
// 查询更新后的年龄
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age
// 使用表达式计算年薪
MATCH (p:Person {name: "张三"})
SET p.annual_salary = p.salary * 12
RETURN p.name, p.salary, p.annual_salary
// 使用字符串拼接
MATCH (p:Person {name: "张三"})
SET p.full_name = p.name + " (" + toString(p.age) + "岁)"
RETURN p.full_name
// 使用条件表达式
MATCH (p:Person {name: "张三"})
SET p.status = CASE
WHEN p.age < 18 THEN "未成年"
WHEN p.age < 60 THEN "成年人"
ELSE "老年人"
END
RETURN p.name, p.age, p.status
// 查询最终状态
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.salary, p.annual_salary, p.full_name, p.status3.5 更新关系属性 #
关系的属性也可以使用SET来更新。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三"}),
(c:Company {name: "科技公司"}),
(p)-[:WORKS_FOR {since: 2020, role: "初级工程师"}]->(c)
// 查询插入后的初始关系数据
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.role, r.since, c.name
// 更新关系属性
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
SET r.role = "高级工程师"
RETURN p.name, r.role, r.since, c.name
// 查询更新后的关系
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.role, r.since, c.name
// 更新关系的多个属性
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
SET r.role = "技术总监", r.since = 2021, r.salary = 20000
RETURN p.name, r.role, r.since, r.salary, c.name
// 使用表达式更新关系属性
MATCH (p:Person)-[r:WORKS_FOR]->(c:Company)
SET r.years = 2024 - r.since
RETURN p.name, r.since, r.years, c.name
// 查询最终状态
MATCH (p:Person)-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.role, r.since, r.salary, r.years, c.name3.6 添加和移除标签 #
标签是节点的分类标识,可以使用SET添加标签,使用REMOVE移除标签。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三", age: 30})
// 查询插入后的初始标签
MATCH (p:Person {name: "张三"})
RETURN p.name, labels(p)
// 添加标签
MATCH (p:Person {name: "张三"})
SET p:Employee
RETURN labels(p), p
// 查询添加标签后的状态
MATCH (p:Person {name: "张三"})
RETURN p.name, labels(p)
// 添加多个标签
MATCH (p:Person {name: "张三"})
SET p:Manager:Senior
RETURN labels(p), p
// 查询节点的所有标签
MATCH (p:Person {name: "张三"})
RETURN p.name, labels(p)
// 移除标签
MATCH (p:Person {name: "张三"})
REMOVE p:Senior
RETURN labels(p), p
// 查询移除标签后的状态
MATCH (p:Person {name: "张三"})
RETURN p.name, labels(p)
// 移除多个标签
MATCH (p:Person {name: "张三"})
REMOVE p:Manager
RETURN labels(p), p
// 查看最终标签
MATCH (p:Person {name: "张三"})
RETURN p.name, labels(p)4. 删除数据(DELETE/REMOVE) #
删除数据是移除节点、关系或属性的操作。在Cypher中,使用DELETE删除节点和关系,使用REMOVE删除属性。
4.1 前置知识:DELETE和REMOVE的区别 #
- DELETE:用于删除节点和关系
- REMOVE:用于删除属性和标签
4.2 删除关系 #
删除关系时,只删除关系本身,不删除关系两端的节点。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p1:Person {name: "张三"}),
(p2:Person {name: "李四"}),
(c1:Company {name: "科技公司"}),
(p1)-[:IS_FRIENDS_WITH]->(p2),
(p1)-[:WORKS_FOR]->(c1)
// 查询删除前的关系
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 删除特定关系
MATCH (p1:Person {name: "张三"})-[r:IS_FRIENDS_WITH]->(p2:Person)
DELETE r
// 查询删除后的关系(朋友关系已删除,工作关系还在)
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 删除所有工作关系
MATCH ()-[r:WORKS_FOR]->()
DELETE r
// 确认节点仍然存在
MATCH (n)
RETURN n4.3 删除节点(DELETE) #
使用DELETE删除节点时,只能删除没有关系的节点。如果节点有关系,必须先删除关系。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p1:Person {name: "张三"}),
(p2:Person {name: "李四"}),
(p3:Person {name: "王五"}),
(p1)-[:IS_FRIENDS_WITH]->(p2)
// 查询插入后的初始数据
MATCH (n)
RETURN n
// 查询节点和关系
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 删除没有关系的节点(可以成功)
MATCH (p:Person {name: "王五"})
DELETE p
// 查询剩余节点
MATCH (n)
RETURN n
// 尝试删除有关系的节点(会失败)
// MATCH (p:Person {name: "张三"})
// DELETE p
// 错误:Cannot delete node<id>, because it still has relationships.
// 先删除关系,再删除节点
MATCH (p1:Person {name: "张三"})-[r:IS_FRIENDS_WITH]->(p2:Person)
DELETE r
// 查询删除关系后的状态
MATCH (n)
RETURN n
MATCH (p:Person {name: "张三"})
DELETE p
// 查询最终结果
MATCH (n)
RETURN n4.4 删除节点及其关系(DETACH DELETE) #
如果要删除一个节点及其所有关系,应该使用DETACH DELETE。这是删除节点的推荐方式。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p1:Person {name: "张三"}),
(p2:Person {name: "李四"}),
(p3:Person {name: "王五"}),
(c1:Company {name: "科技公司"}),
(p1)-[:IS_FRIENDS_WITH]->(p2),
(p1)-[:IS_FRIENDS_WITH]->(p3),
(p1)-[:WORKS_FOR]->(c1)
// 查询删除前的图结构
MATCH (p:Person)-[r]->(target)
RETURN p.name, type(r), target.name
// 使用 DETACH DELETE 删除节点及其所有关系
MATCH (p:Person {name: "张三"})
DETACH DELETE p
// 查询删除后的结果(张三及其所有关系都被删除)
MATCH (n)
RETURN n
// 删除所有节点及其关系
MATCH (n)
DETACH DELETE n
// 确认数据库已清空
MATCH (n)
RETURN count(n) AS node_count4.5 删除属性(REMOVE) #
可以使用REMOVE删除节点或关系的属性。
// 清空数据库
MATCH (n) DETACH DELETE n
// 创建测试数据
CREATE (p:Person {name: "张三", age: 30, city: "北京", email: "zhangsan@example.com"}),
(c:Company {name: "科技公司"}),
(p)-[:WORKS_FOR {since: 2020, role: "工程师", salary: 10000}]->(c)
// 查询插入后的初始节点属性
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.city, p.email
// 查询插入后的初始关系属性
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.since, r.role, r.salary, c.name
// 删除节点的单个属性
MATCH (p:Person {name: "张三"})
REMOVE p.email
RETURN p
// 查询删除后的属性
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.city, p.email
// 删除节点的多个属性
MATCH (p:Person {name: "张三"})
REMOVE p.city, p.age
RETURN p
// 查询删除多个属性后的状态
MATCH (p:Person {name: "张三"})
RETURN p.name, p.age, p.city, p.email
// 删除关系属性
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
REMOVE r.salary
RETURN p.name, r.since, r.role, r.salary, c.name
// 查询删除关系属性后的状态
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r.since, r.role, r.salary, c.name
// 删除关系的多个属性
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
REMOVE r.role, r.since
RETURN p.name, r, c.name
// 查询最终状态
MATCH (p:Person {name: "张三"})-[r:WORKS_FOR]->(c:Company)
RETURN p.name, r, c.name5. 避免重复数据(MERGE) #
MERGE是Cypher中非常重要的命令,它确保数据存在(不存在时创建),避免重复数据。
5.1 前置知识:为什么需要MERGE? #
在使用CREATE创建数据时,如果多次执行相同的CREATE语句,会创建重复的节点。MERGE可以解决这个问题:
- 如果数据不存在:创建新数据
- 如果数据已存在:匹配现有数据(不创建重复数据)
5.2 MERGE节点 #
使用MERGE可以确保节点只创建一次。
// 清空数据库
MATCH (n) DETACH DELETE n
// 查询初始状态(应该为空)
MATCH (p:Person)
RETURN count(p) AS initial_count
// 第一次执行 MERGE:节点不存在,会创建
MERGE (p:Person {name: "张三", email: "zhangsan@example.com"})
RETURN p
// 查询第一次 MERGE 后的节点
MATCH (p:Person)
RETURN p.name, p.email, count(p) AS count
// 第二次执行相同的 MERGE:节点已存在,不会创建重复节点
MERGE (p:Person {name: "张三", email: "zhangsan@example.com"})
RETURN p
// 查询节点(只有一个节点,证明没有重复创建)
MATCH (p:Person)
RETURN p.name, p.email, count(p) AS count
// 对比:使用 CREATE 会创建重复节点
CREATE (p:Person {name: "李四", email: "lisi@example.com"})
CREATE (p:Person {name: "李四", email: "lisi@example.com"})
// 查询(会有两个重复的节点)
MATCH (p:Person {name: "李四"})
RETURN p.name, p.email, count(p) AS count
// 使用 MERGE 避免重复
MERGE (p:Person {name: "王五", email: "wangwu@example.com"})
MERGE (p:Person {name: "王五", email: "wangwu@example.com"})
// 查询(只有一个节点)
MATCH (p:Person {name: "王五"})
RETURN p.name, p.email, count(p) AS count
// 查询所有节点
MATCH (p:Person)
RETURN p.name, p.email5.3 MERGE关系 #
也可以使用MERGE来确保关系只创建一次。
// 清空数据库
MATCH (n) DETACH DELETE n
// 先创建节点
CREATE (p1:Person {name: "张三"}),
(p2:Person {name: "李四"}),
(c1:Company {name: "科技公司"})
// 查询插入后的初始节点
MATCH (n)
RETURN n
// 查询初始关系(应该为空)
MATCH (p1:Person {name: "张三"})-[r:IS_FRIENDS_WITH]->(p2:Person {name: "李四"})
RETURN count(r) AS initial_relationship_count
// 使用 MERGE 创建关系(第一次)
MATCH (p1:Person {name: "张三"}),
(p2:Person {name: "李四"})
MERGE (p1)-[:IS_FRIENDS_WITH]->(p2)
RETURN p1.name, p2.name
// 查询第一次 MERGE 后的关系
MATCH (p1:Person {name: "张三"})-[r:IS_FRIENDS_WITH]->(p2:Person {name: "李四"})
RETURN count(r) AS relationship_count
// 再次执行相同的 MERGE(不会创建重复关系)
MATCH (p1:Person {name: "张三"}),
(p2:Person {name: "李四"})
MERGE (p1)-[:IS_FRIENDS_WITH]->(p2)
RETURN p1.name, p2.name
// 查询关系(只有一条,证明没有重复创建)
MATCH (p1:Person {name: "张三"})-[r:IS_FRIENDS_WITH]->(p2:Person {name: "李四"})
RETURN count(r) AS relationship_count
// MERGE 节点和关系一起
MERGE (p:Person {name: "王五", email: "wangwu@example.com"})
MERGE (c:Company {name: "互联网公司"})
MERGE (p)-[:WORKS_FOR]->(c)
RETURN p.name, c.name
// 查询 MERGE 后的节点和关系
MATCH (p:Person {name: "王五"})-[r:WORKS_FOR]->(c:Company {name: "互联网公司"})
RETURN p.name, c.name, count(r) AS relationship_count
// 再次执行(不会创建重复)
MERGE (p:Person {name: "王五", email: "wangwu@example.com"})
MERGE (c:Company {name: "互联网公司"})
MERGE (p)-[:WORKS_FOR]->(c)
RETURN p.name, c.name
// 查询最终状态(关系数量应该不变)
MATCH (p:Person {name: "王五"})-[r:WORKS_FOR]->(c:Company {name: "互联网公司"})
RETURN p.name, c.name, count(r) AS relationship_count5.4 ON CREATE SET 和 ON MATCH SET #
可以在MERGE时使用ON CREATE SET和ON MATCH SET来分别处理创建和匹配的情况。
// 清空数据库
MATCH (n) DETACH DELETE n
// 查询初始状态(应该为空)
MATCH (p:Person {email: "zhangsan@example.com"})
RETURN count(p) AS initial_count
// 第一次 MERGE:节点不存在,执行 ON CREATE SET
MERGE (p:Person {email: "zhangsan@example.com"})
ON CREATE SET p.name = "张三", p.created_at = timestamp(), p.visit_count = 1
ON MATCH SET p.visit_count = p.visit_count + 1, p.last_visit = timestamp()
RETURN p
// 查询第一次 MERGE 后的节点(应该执行了 ON CREATE SET)
MATCH (p:Person {email: "zhangsan@example.com"})
RETURN p.name, p.email, p.visit_count, p.created_at, p.last_visit
// 第二次 MERGE:节点已存在,执行 ON MATCH SET
MERGE (p:Person {email: "zhangsan@example.com"})
ON CREATE SET p.name = "张三", p.created_at = timestamp(), p.visit_count = 1
ON MATCH SET p.visit_count = p.visit_count + 1, p.last_visit = timestamp()
RETURN p
// 查询节点(visit_count 应该增加了)
MATCH (p:Person {email: "zhangsan@example.com"})
RETURN p.name, p.email, p.visit_count, p.created_at, p.last_visit
// 再次执行 MERGE
MERGE (p:Person {email: "zhangsan@example.com"})
ON CREATE SET p.name = "张三", p.created_at = timestamp(), p.visit_count = 1
ON MATCH SET p.visit_count = p.visit_count + 1, p.last_visit = timestamp()
RETURN p.visit_count
// 查看最终结果
MATCH (p:Person {email: "zhangsan@example.com"})
RETURN p.name, p.visit_count, p.created_at, p.last_visit5.5 MERGE最佳实践 #
使用MERGE时,应该使用唯一标识符(如email、ID等)作为匹配条件。
// 清空数据库
MATCH (n) DETACH DELETE n
// 查询初始状态
MATCH (n)
RETURN count(n) AS initial_count
// 最佳实践:使用唯一标识符(email)作为匹配条件
MERGE (p:Person {email: "zhangsan@example.com"})
ON CREATE SET p.name = "张三", p.created_at = timestamp()
ON MATCH SET p.last_updated = timestamp()
RETURN p
// 查询 MERGE 后的节点
MATCH (p:Person {email: "zhangsan@example.com"})
RETURN p.name, p.email, p.created_at, p.last_updated
// 最佳实践:使用 ID 作为唯一标识符
MERGE (c:Company {id: "COMP001"})
ON CREATE SET c.name = "科技公司", c.created_at = timestamp()
RETURN c
// 查询 MERGE 后的公司
MATCH (c:Company {id: "COMP001"})
RETURN c.name, c.id, c.created_at
// ❌ 不推荐:使用非唯一属性(name)作为匹配条件,可能创建重复节点
MERGE (p:Person {name: "张三"})
RETURN p
// 查询使用 name 匹配的节点
MATCH (p:Person {name: "张三"})
RETURN p.name, p.email, count(p) AS count
// 推荐:组合唯一属性
MERGE (p:Person {email: "zhangsan@example.com", id: "P001"})
ON CREATE SET p.name = "张三"
RETURN p
// 查询组合唯一属性的节点
MATCH (p:Person {email: "zhangsan@example.com", id: "P001"})
RETURN p.name, p.email, p.id
// 最佳实践:MERGE 节点和关系时,确保节点已存在或使用 MERGE
MERGE (p:Person {email: "lisi@example.com"})
ON CREATE SET p.name = "李四"
MERGE (c:Company {id: "COMP001"})
ON CREATE SET c.name = "科技公司"
MERGE (p)-[:WORKS_FOR {since: 2020}]->(c)
RETURN p.name, c.name
// 查询结果
MATCH (p:Person)-[r:WORKS_FOR]->(c:Company)
RETURN p.name, c.name, r.since
// 查询最终状态
MATCH (n)
RETURN labels(n), count(n) AS count6. 小结 #
6.1 核心概念回顾 #
介绍了Cypher中数据创建、更新和删除的核心操作:
| 操作类型 | 命令 | 说明 | 示例 |
|---|---|---|---|
| 创建节点 | CREATE (n:Label {property: value}) |
创建新节点 | CREATE (p:Person {name: 'John'}) |
| 创建关系 | CREATE (a)-[:REL]->(b) |
创建新关系 | CREATE (a)-[:KNOWS]->(b) |
| 更新属性 | SET n.property = value |
更新节点或关系的属性 | SET p.age = 30 |
| 删除关系 | DELETE r |
删除关系 | DELETE r |
| 删除节点 | DELETE n 或 DETACH DELETE n |
删除节点 | DETACH DELETE n |
| 删除属性 | REMOVE n.property |
删除属性 | REMOVE p.email |
| 避免重复 | MERGE (n:Label {id: value}) |
存在则匹配,不存在则创建 | MERGE (p:Person {email: '...'}) |
6.2 CREATE vs MERGE 对比 #
| 特性 | CREATE | MERGE |
|---|---|---|
| 行为 | 总是创建新数据 | 存在则匹配,不存在则创建 |
| 重复数据 | 可能创建重复数据 | 避免重复数据 |
| 使用场景 | 确定要创建新数据时 | 避免重复数据时 |
| 性能 | 较快 | 较慢(需要检查是否存在) |
6.3 DELETE vs DETACH DELETE 对比 #
| 特性 | DELETE | DETACH DELETE |
|---|---|---|
| 删除节点 | 只能删除无关系的节点 | 删除节点及其所有关系 |
| 删除关系 | 可以删除关系 | 不单独删除关系 |
| 安全性 | 如果节点有关系会失败 | 总是成功 |
| 使用场景 | 确定节点没有关系时 | 删除节点及其所有关系时(推荐) |
6.4 最佳实践 #
创建数据
- 使用CREATE创建确定要新建的数据
- 使用MERGE避免重复数据
- 在MERGE中使用唯一标识符(如email、ID)
更新数据
- 使用SET更新属性
- 可以一次更新多个属性
- 使用表达式计算新值
删除数据
- 使用DETACH DELETE删除节点(更安全)
- 删除前先查询确认
- 使用REMOVE删除属性
避免重复
- 使用MERGE避免重复创建
- 在MERGE中使用唯一标识符
- 使用ON CREATE和ON MATCH处理不同情况
6.5 常见错误和解决方案 #
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 无法删除有关系的节点 | 节点仍有关联关系 | 使用DETACH DELETE |
| MERGE创建了重复节点 | 匹配条件不唯一 | 使用唯一标识符(如email、ID) |
| 更新属性失败 | 节点不存在 | 先使用MATCH确认节点存在,或使用MERGE |
| CREATE创建了重复数据 | 多次执行相同的CREATE | 使用MERGE代替CREATE |