教程目录 引自:https://neo4j.com/docs/getting-started/cypher-intro/updating/
更新数据
之前您学习了如何在 Cypher® 中表示节点、关系、标签、属性和模式。本节通过介绍如何使用 Cypher 更新和删除数据,在您的知识中添加另一个层次。
虽然这些是标准的 CRUD(创建、读取、更新和删除)操作,但与在其他类型的数据库中相比,某些功能在图中有所不同。当我们进行时,您可能会认识到一些相似之处和不同之处。
使用 Cypher 更新数据
您可能已经在数据中有一个节点或关系,但您想修改其属性。您可以通过匹配要查找的模式并使用 SET
关键字来添加、删除或更新属性来执行此操作。
我们继续使用以下数据集:
图 1. 图:人员、他们工作的公司以及他们喜欢的技术
要创建上述图,请运行 Cypher 查询:
CREATE (diana:Person {name: "Diana"})
CREATE (melissa:Person {name: "Melissa", twitter: "@melissa"})
CREATE (dan:Person {name: "Dan", twitter: "@dan", yearsExperience: 6})
CREATE (sally:Person {name: "Sally", yearsExperience: 4})
CREATE (john:Person {name: "John", yearsExperience: 5})
CREATE (jennifer:Person {name: "Jennifer", twitter: "@jennifer", yearsExperience: 5})
CREATE (joe:Person {name: "Joe"})
CREATE (mark:Person {name: "Mark", twitter: "@mark"})
CREATE (ann:Person {name: "Ann"})
CREATE (xyz:Company {name: "XYZ"})
CREATE (x:Company {name: "Company X"})
CREATE (a:Company {name: "Company A"})
CREATE (Neo4j:Company {name: "Neo4j"})
CREATE (abc:Company {name: "ABC"})
CREATE (query:Technology {type: "Query Languages"})
CREATE (etl:Technology {type: "Data ETL"})
CREATE (integrations:Technology {type: "Integrations"})
CREATE (graphs:Technology {type: "Graphs"})
CREATE (dev:Technology {type: "Application Development"})
CREATE (java:Technology {type: "Java"})
CREATE (diana)-[:LIKES]->(query)
CREATE (melissa)-[:LIKES]->(query)
CREATE (dan)-[:LIKES]->(etl)<-[:LIKES]-(melissa)
CREATE (xyz)<-[:WORKS_FOR]-(sally)-[:LIKES]->(integrations)<-[:LIKES]-(dan)
CREATE (sally)<-[:IS_FRIENDS_WITH]-(john)-[:LIKES]->(java)
CREATE (john)<-[:IS_FRIENDS_WITH]-(jennifer)-[:LIKES]->(java)
CREATE (john)-[:WORKS_FOR]->(xyz)
CREATE (sally)<-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]->(melissa)
CREATE (joe)-[:LIKES]->(query)
CREATE (x)<-[:WORKS_FOR]-(diana)<-[:IS_FRIENDS_WITH]-(joe)-[:IS_FRIENDS_WITH]->(mark)-[:LIKES]->(graphs)<-[:LIKES]-(jennifer)-[:WORKS_FOR]->(Neo4j)
CREATE (ann)<-[:IS_FRIENDS_WITH]-(jennifer)-[:IS_FRIENDS_WITH]->(mark)
CREATE (john)-[:LIKES]->(dev)<-[:LIKES]-(ann)-[:IS_FRIENDS_WITH]->(dan)-[:WORKS_FOR]->(abc)
CREATE (ann)-[:WORKS_FOR]->(abc)
CREATE (a)<-[:WORKS_FOR]-(melissa)-[:LIKES]->(graphs)<-[:LIKES]-(diana)
到目前为止,使用上面的示例数据集,您可以更新 Jennifer 的节点以添加她的出生日期。下一个 Cypher 语句显示了如何执行此操作。
- 首先,您需要找到 Jennifer 的现有节点。
- 接下来,使用
SET
创建新属性(使用语法variable.property
)并设置其值。 - 最后,您可以返回 Jennifer 的节点以确保信息已正确更新。
MATCH (p:Person {name: 'Jennifer'})
SET p.birthdate = date('1980-01-01')
RETURN p
查询结果:
Set Properties: 1
Rows: 1
+------------------------------------------------------+
| p |
+------------------------------------------------------+
|(Person: {birthdate: '1980-01-01', name: 'Jennifer'}) |
+------------------------------------------------------+
有关使用 date()
和其他时间函数的更多信息,请访问 Cypher 手册 → 时间函数。
如果要更改 Jennifer 的出生日期,可以使用上面的同一查询再次找到 Jennifer 的节点,并在 SET
子句中放入不同的日期。
您还可以使用 Company
节点更新 Jennifer 的 WORKS_FOR
关系,以包括她开始在那里工作的年份。为此,您可以使用与上面类似的语法来更新节点。
MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'})
SET rel.startYear = date({year: 2018})
RETURN rel
查询结果:
Set Properties: 1
Rows: 1
+-----------------------------------------+
| rel |
+-----------------------------------------+
| [:WORKS_FOR {startYear: '2018-01-01'}] |
+-----------------------------------------+
如果要返回上述查询的图视图,可以将变量添加到节点 p:Person
和 c:Company
,并将返回行写为 RETURN p, rel, c
。
使用 Cypher 删除数据
要介绍的另一个操作是如何在 Cypher 中删除数据。对于此操作,Cypher 使用 DELETE
关键字删除节点和关系。它与其他语言(如 SQL)中删除数据非常相似,但有一个例外。
由于 Neo4j 符合 ACID,因此如果节点仍具有关系,则无法删除该节点。如果可以这样做,那么您最终可能会得到指向空的关系和不完整的图。
删除关系
要删除关系,您需要找到要删除的关系的开始和结束节点,然后使用 DELETE
关键字,如下面的代码块所示。让我们继续删除 Jennifer 和 Mark 之间的 IS_FRIENDS_WITH
关系。我们稍后将在练习中重新添加此关系。
MATCH (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
DELETE r
查询结果:
+-----------------------------------------+
| Deleted Relationships: 1 |
| Rows: 0 |
+-----------------------------------------+
删除节点
要删除没有任何关系的节点,您需要找到要删除的节点,然后使用 DELETE
关键字,就像您对上面的关系所做的那样。您可以暂时删除 Mark 的节点,稍后再将其恢复。
MATCH (m:Person {name: 'Mark'})
DELETE m
查询结果:
+-----------------------------------------+
| Deleted Nodes: 1 |
| Rows: 0 |
+-----------------------------------------+
如果您错误地创建了一个空节点并且需要删除它,您可以使用以下 Cypher 语句来执行此操作:
MATCH (n)
WHERE id(n) = 5
DETACH DELETE n
此语句不仅删除节点,还删除它具有的所有关系。要运行该语句,您应该知道节点的内部 ID。
删除节点及其关系
您可以运行单个语句来删除节点及其关系,而不是运行最后两个查询来删除 IS_FRIENDS_WITH
关系和 Mark 的 Person
节点。如上所述,Neo4j 符合 ACID,因此不允许删除仍具有关系的节点。使用 DETACH DELETE
语法告诉 Cypher 删除节点具有的任何关系,并删除节点本身。
该语句如下面的代码所示。首先,您在数据库中找到 Mark 的节点。然后,DETACH DELETE
行删除 Mark 节点具有的任何现有关系,然后再删除该节点。
MATCH (m:Person {name: 'Mark'})
DETACH DELETE m
删除属性
您还可以删除属性,但您可以使用其他几种方法,而不是使用 DELETE
关键字。
- 第一种选择是在属性上使用
REMOVE
。这告诉 Neo4j 您要从节点中完全删除该属性,并且不再存储它。 - 第二个选项是使用之前的
SET
关键字将属性值设置为 null。与其他数据库模型不同,Neo4j 不存储空值。相反,它只存储对您的数据有意义的属性和值。这意味着您可以在图中的各种节点和关系上具有不同类型和数量的属性。
为了向您展示这两种选择,让我们看一下每种方法的代码。
//delete property using REMOVE keyword
MATCH (n:Person {name: 'Jennifer'})
REMOVE n.birthdate
//delete property with SET to null value
MATCH (n:Person {name: 'Jennifer'})
SET n.birthdate = null
查询结果:
+-----------------------------------------+
| Set Properties: 1 |
| Rows: 0 |
+-----------------------------------------+
使用 MERGE 避免重复数据
前面简要提到了 Cypher 中有一些方法可以避免创建重复数据。其中一种方法是使用 MERGE
关键字。MERGE
执行“选择或插入”操作,该操作首先检查数据库中是否存在数据。如果存在,则 Cypher 按原样返回它,或者对现有节点或关系进行您指定的任何更新。如果数据不存在,则 Cypher 将使用您指定的信息创建它。
在节点上使用 MERGE
首先,让我们通过使用下面的查询将 Mark 添加回我们的数据库来查看一个示例。您可以使用 MERGE
来确保 Cypher 检查数据库中是否存在 Mark 的现有节点。由于您在前面的示例中删除了 Mark 的节点,因此 Cypher 将找不到现有匹配项,并将使用设置为“Mark”的名称属性创建一个新节点。
MERGE (mark:Person {name: 'Mark'})
RETURN mark
查询结果:
(插入图表链接)
如果再次运行相同的语句,Cypher 这次将找到一个名称属性设置为 Mark 的现有节点,因此它将返回匹配的节点,而不会进行任何更改。
在关系上使用 MERGE
就像您使用 MERGE
在 Cypher 中查找或创建节点一样,您可以执行相同的操作来查找或创建关系。让我们重新创建我们在先前示例中拥有的 Mark 和 Jennifer 之间的 IS_FRIENDS_WITH
关系。
MATCH (j:Person {name: 'Jennifer'})
MATCH (m:Person {name: 'Mark'})
MERGE (j)-[r:IS_FRIENDS_WITH]->(m)
RETURN j, r, m
请注意,此处使用 MATCH
在使用 MERGE
查找或创建它们之间关系之前查找 Mark 的节点和 Jennifer 的节点。
为什么我们不使用单个语句?
MERGE
查找您指定的整个模式,以查看是返回现有模式还是创建新模式。如果整个模式(节点、关系和任何指定的属性)不存在,则 Cypher 会创建它。
Cypher 永远不会在模式中产生匹配和创建的部分混合。为避免匹配和创建的混合,您需要在对可能要创建的任何元素执行合并之前,首先匹配模式的任何现有元素,就像我们在上面的语句中所做的那样。
(插入图表链接)
仅供参考,导致重复项的 Cypher 语句如下。由于此模式(Jennifer IS_FRIENDS_WITH Mark)在数据库中不存在,因此 Cypher 会创建一个全新的模式 - 两个节点以及它们之间的关系。
//this statement will create duplicate nodes for Mark and Jennifer
MERGE (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
RETURN j, r, m
处理 MERGE 标准
也许您想使用 MERGE
来确保您不创建重复项,但是如果创建了模式,您想初始化某些属性,如果仅匹配了模式,则要更新其他属性。在这种情况下,您可以将 ON CREATE
或 ON MATCH
与 SET
关键字一起使用来处理这些情况。
让我们看一个例子。
MERGE (m:Person {name: 'Mark'})-[r:IS_FRIENDS_WITH]-(j:Person {name:'Jennifer'})
ON CREATE SET r.since = date('2018-03-01')
ON MATCH SET r.updated = date()
RETURN m, r, j
资源
- Neo4j Cypher 手册:CREATE
- Neo4j Cypher 手册:SET
- Neo4j Cypher 手册:REMOVE
- Neo4j Cypher 手册:DELETE
- Neo4j Cypher 手册:MERGE
- Neo4j Cypher 手册:ON CREATE/ON MATCH