309 lines
7.4 KiB
Markdown
309 lines
7.4 KiB
Markdown
|
|
## 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;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|