meface/docs/article/db/neo4j_cypher.md

309 lines
7.4 KiB
Markdown
Raw Permalink Normal View History

2026-01-26 10:24:37 +08:00
## Neo4j的cyhper基本语法
### 1. 创建节点和关系
#### 1.1创建节点
```sql
create (n)
create (n),(m)
create(n:Movie)
create(n:Movie:Person)
# 创建一个带有标签Person和属性name:'TEST-NAME', age:1的节点
create(n:Person {name:'qiusj',age:18})
# 返回创建的节点
CREATE(n:TEST {name:'TEST-NAME1', age:2}) return n
```
#### 1.2 创建关系
```sql
# 创建两个节点之间的关系
MATCH (a:TEST),(b:TEST)
WHERE a.name = 'TEST-NAME' AND b.name = 'TEST-NAME1'
CREATE (a)-[r:RELTYPE] -> (b)
RETURN r
# 创建两个节点之间的关系,并调用两个节点的属性:
MATCH (a:TEST),(b:TEST)
WHERE a.name = 'TEST-NAME' AND b.name = 'TEST-NAME1'
CREATE (a)-[r:RELTYPE { name: a.name + b.name}] -> (b)
RETURN r
```
#### 1.3 `merge` 命令
在Neo4j数据库中**MERGE**命令是一个非常强大的工具,它结合了**CREATE**和**MATCH**命令的功能。当你需要确保一个特定的节点或关系在图中存在时MERGE命令就显得尤为重要。如果该节点或关系不存在MERGE将会创建它如果已经存在MERGE则会匹配到这个现有的元素。
> 如果这个节点已经存在那么MERGE命令的作用就相当于MATCH命令。判断是否存在的方式是表达式中所有的属性组合匹配的如 MERGE (p:Person {name: 'Alice'}) RETURN p;只要在已有的Person中name属性没有等于'Alice'的就是不存在MERGE (p:Person {name: 'Alice,age:18}) 则要求现有的Person中的name和age都不相同才表示不存在
```sql
MERGE (robert:Person { name: 'Robert' })
RETURN robert, labels(robert)
```
MERGE还可以用来创建节点之间的关系。如果两个节点之间的关系不存在MERGE会创建这个关系。例如以下命令会创建一个名为"Robert"的Person节点和一个名为"hanscal"的Person节点之间的FAMILY关系:
```sql
MATCH (n:Person { name: 'Robert' }), (m:Person { name: "hanscal" })
MERGE (n)-[r:FAMILY]->(m)
RETURN n.name, type(r), m.name
```
**使用ON CREATE和ON MATCH**
MERGE命令可以与**ON CREATE**和**ON MATCH**子句结合使用,这允许你根据元素是被匹配到还是被创建来执行不同的操作。例如,以下命令在创建新节点时设置一个时间戳属性:
```sql
MERGE (c:Person { name: 'Hanscal' })
ON CREATE SET c.create = timestamp()
RETURN c.name, c.create
```
如果节点"Hanscal"已经存在,则不会设置任何属性。相反,如果使用**ON MATCH**,则只有在匹配到节点时才会设置属性。
**批量操作**
MERGE命令也可以用于批量操作快速创建大量的节点和关系。例如以下命令会将所有Person节点的出生地属性与City节点连接起来并创建BORN_IN关系
```sql
MATCH (person:Person)
MERGE (city:City { name: person.bornIn })
MERGE (person)-[r:BORN_IN]->(city)
RETURN person.name, person.bornIn, city
```
总的来说,`MERGE`命令在确保数据一致性和避免重复创建相同的元素时非常有用。
**约束与 MERGE 命令的关系**
- **唯一性约束**:确保指定标签的节点在特定属性上具有唯一性,是 Neo4j 保证数据完整性的重要机制
- MERGE 命令行为:
- 若匹配条件的节点 / 关系存在,则返回现有节点 / 关系
- 若不存在,则创建新的节点 / 关系
- **冲突点**:当 MERGE 的匹配条件触发唯一性约束时,会因重复数据导致操作失败
#### 1.4 添加属性
方案 1使用 MATCH 而非 MERGE推荐
```sql
MATCH (p:Person {name: 'Robert'})
SET p.age = 18
RETURN p;
```
方案 2修改 MERGE 语句避免重复创建
```sql
# 安全的MERGE写法先检查节点是否存在
MERGE (p:Person {name: 'Robert'})
# 仅当节点不存在时才创建新属性(避免冲突)
ON CREATE SET p.create = timestamp()
# 无论是否创建都可以设置属性(不会触发约束)
SET p.money = 1
RETURN p;
```
#### 1.5 修改节点的关系类型
在 Neo4j 中关系类型Relationship Type是不可变的无法直接修改。若要更改关系类型需通过以下步骤实现**创建新关系 → 复制属性 → 删除旧关系**。以下是详细方法:
**方法一:使用 Cypher 手动转换关系类型**
```sql
// 示例:将 KNOWS 关系转换为 FRIEND 关系
MATCH (p1:Person)-[r:KNOWS]->(p2:Person)
WHERE p1.name = 'Alice' AND p2.name = 'Bob'
// 创建新类型的关系
CREATE (p1)-[r2:FRIEND]->(p2)
// 复制旧关系的所有属性到新关系
SET r2 = r
// 删除旧关系
DELETE r
RETURN p1, r2, p2;
```
### 2.查询语法
> match、optional match、where、start和aggregation聚合
#### 2.1 match语法
**简单查询**
```sql
# 查询所有节点
match (n) return n
# 查询指定标签的节点
match (n:Person) return n
# 查询指定标签和属性的节点
match (n:Person {name:"张三"}) return n
```
**关系查询**
```sql
# 查询出度1的节点
match (n:Person{name:"张三"})-[r]->(m) return m
match (n:Person{name:"zhangsan"})-->(m) return m
# 查询入度1节点:
match (n:Person{name:"zhangsan"})<-[r]-(m) return m
match (n:Person{name:"zhangsan"})<--(m) return m
```
### 3.删除节点
- 删除无关系的孤立节点
使用`DELETE`语句直接删除节点
```sql
// 删除单个节点(无关系)
MATCH (p:Person {name: 'Alice'})
DELETE p;
// 批量删除符合条件的节点
MATCH (p:Person)
WHERE p.age < 18
DELETE p;
```
- 删除带有关联关系的节点
需先删除关系,再删除节点。可使用`DETACH DELETE`一次性完成:
```sql
// 方法1分步删除手动删除关系
MATCH (p:Person {name: 'Bob'})-[r]->()
DELETE r; // 先删除所有外出关系
MATCH (p:Person {name: 'Bob'})
DELETE p; // 再删除节点
// 方法2使用DETACH DELETE推荐
MATCH (p:Person {name: 'Charlie'})
DETACH DELETE p; // 自动删除节点及其所有关系
```
- 基于关系条件删除节点
删除符合特定关系条件的节点:
```sql
// 删除所有没有朋友的人无FOLLOWS关系
MATCH (p:Person)
WHERE NOT (p)-[:FOLLOWS]->()
DELETE p;
// 删除被超过100人关注的明星节点
MATCH (s:Star)<-[r:FOLLOWS]-()
WITH s, count(r) as followers
WHERE followers > 100
DETACH DELETE s;
```
- 删除整个标签的所有节点
```sql
// 删除所有Person节点及其关系
MATCH (p:Person)
DETACH DELETE p;
// 更安全的分批删除方法
CALL apoc.periodic.iterate(
"MATCH (p:Person) RETURN p",
"DETACH DELETE p",
{batchSize:1000, parallel:false}
);
```
- 删除节点并返回删除数量
```sql
MATCH (p:Person)
WHERE p.lastLogin < date("2023-01-01")
DETACH DELETE p
RETURN count(*) as deletedNodes;
```
### 4. 删除关系
场景一:删除特定关系
```sql
// 方法1通过匹配节点和关系类型删除
MATCH (p1:Person {name: 'Alice'})-[r:FRIEND]->(p2:Person {name: 'Bob'})
DELETE r;
// 方法2使用更精确的匹配条件如属性
MATCH (p1:Person)-[r:WORKS_ON {projectId: 'PRJ-123'}]->(p2:Project)
DELETE r;
```
场景二只有查询返回的ID
```sql
// 方法1使用关系ID直接删除
MATCH ()-[r]->()
WHERE id(r) = 5678 // 替换为实际关系ID
DELETE r; // 仅删除关系,保留节点
// 方法2验证关系后删除
MATCH ()-[r]->()
WHERE id(r) = 5678
RETURN r; // 先查询确认关系是否存在
// 确认无误后执行删除
MATCH ()-[r]->()
WHERE id(r) = 5678
DELETE r;
```