导航菜单

  • 1.langchain.intro
  • 2.langchain.chat_models
  • 3.langchain.prompts
  • 4.langchain.example_selectors
  • 5.output_parsers
  • 6.Runnable
  • 7.memory
  • 8.document_loaders
  • 9.text_splitters
  • 10.embeddings
  • 11.tool
  • 12.retrievers
  • 13.optimize
  • 14.项目介绍
  • 15.启动HTTP
  • 16.数据与模型
  • 17.权限管理
  • 18.知识库管理
  • 19.设置
  • 20.文档管理
  • 21.聊天
  • 22.API文档
  • 23.RAG优化
  • 24.索引时优化
  • 25.检索前优化
  • 26.检索后优化
  • 27.系统优化
  • 28.GraphRAG
  • 29.图
  • 30.为什么选择图数据库
  • 31.什么是 Neo4j
  • 32.安装和连接 Neo4j
  • 33.Neo4j核心概念
  • 34.Cypher基础
  • 35.模式匹配
  • 36.数据CRUD操作
  • 37.GraphRAG
  • 38.查询和过滤
  • 39.结果处理和聚合
  • 40.语句组合
  • 41.子查询
  • 42.模式和约束
  • 43.日期时间处理
  • 44.Cypher内置函数
  • 45.Python操作Neo4j
  • 46.neo4j
  • 47.py2neo
  • 48.Streamlit
  • 49.Pandas
  • 50.graphRAG
  • 51.deepdoc
  • 52.deepdoc
  • 53.deepdoc
  • 55.deepdoc
  • 54.deepdoc
  • Pillow
  • 1. 什么是CRUD操作
  • 2. 创建数据(CREATE)
    • 2.1 CREATE命令的基本语法
    • 2.2 创建节点
    • 2.3 创建带多个属性的节点
    • 2.4 创建关系
    • 2.5 创建复杂图结构
  • 3. 更新数据(SET)
    • 3.1 前置知识:SET命令
    • 3.2 更新节点属性
    • 3.3 更新多个属性
    • 3.4 使用表达式更新属性
    • 3.5 更新关系属性
    • 3.6 添加和移除标签
  • 4. 删除数据(DELETE/REMOVE)
    • 4.1 前置知识:DELETE和REMOVE的区别
    • 4.2 删除关系
    • 4.3 删除节点(DELETE)
    • 4.4 删除节点及其关系(DETACH DELETE)
    • 4.5 删除属性(REMOVE)
  • 5. 避免重复数据(MERGE)
    • 5.1 前置知识:为什么需要MERGE?
    • 5.2 MERGE节点
    • 5.3 MERGE关系
    • 5.4 ON CREATE SET 和 ON MATCH SET
    • 5.5 MERGE最佳实践
  • 6. 小结
    • 6.1 核心概念回顾
    • 6.2 CREATE vs MERGE 对比
    • 6.3 DELETE vs DETACH DELETE 对比
    • 6.4 最佳实践
    • 6.5 常见错误和解决方案

1. 什么是CRUD操作 #

在数据库操作中,CRUD是最基本的四个操作:

  • Create(创建):创建新的数据
  • Read(读取):查询和读取数据
  • Update(更新):修改现有数据
  • Delete(删除):删除数据

在图数据库中,CRUD操作有一些特殊之处:

  1. 创建:可以创建节点和关系,以及它们的属性
  2. 更新:可以更新节点和关系的属性,也可以添加或删除标签
  3. 删除:可以删除节点、关系或属性,但需要注意节点和关系之间的依赖关系

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 n

2.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.city

2.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.name

2.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.since

3. 更新数据(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.city

3.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_time

3.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.status

3.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.name

3.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 n

4.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 n

4.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_count

4.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.name

5. 避免重复数据(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.email

5.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_count

5.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_visit

5.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 count

6. 小结 #

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 最佳实践 #

  1. 创建数据

    • 使用CREATE创建确定要新建的数据
    • 使用MERGE避免重复数据
    • 在MERGE中使用唯一标识符(如email、ID)
  2. 更新数据

    • 使用SET更新属性
    • 可以一次更新多个属性
    • 使用表达式计算新值
  3. 删除数据

    • 使用DETACH DELETE删除节点(更安全)
    • 删除前先查询确认
    • 使用REMOVE删除属性
  4. 避免重复

    • 使用MERGE避免重复创建
    • 在MERGE中使用唯一标识符
    • 使用ON CREATE和ON MATCH处理不同情况

6.5 常见错误和解决方案 #

错误 原因 解决方案
无法删除有关系的节点 节点仍有关联关系 使用DETACH DELETE
MERGE创建了重复节点 匹配条件不唯一 使用唯一标识符(如email、ID)
更新属性失败 节点不存在 先使用MATCH确认节点存在,或使用MERGE
CREATE创建了重复数据 多次执行相同的CREATE 使用MERGE代替CREATE
← 上一节 35.模式匹配 下一节 37.GraphRAG →

访问验证

请输入访问令牌

Token不正确,请重新输入