更新数据
您之前学习了如何在 Cypher® 中表示节点、关系、标签、属性和模式。本节将介绍如何在 Cypher 中更新和删除数据,使您的知识更上一层楼。
虽然这些是标准的 CRUD(创建、更新和删除)操作,但在图数据库中,某些操作与其他类型的数据库略有不同。在接下来的内容中,您可能会发现一些相似之处和差异。
使用 Cypher 更新数据
您可能已经在数据中拥有一个节点或关系,但想要修改其属性。您可以通过匹配要查找的模式并使用 SET
关键字添加、删除或更新属性来实现。
我们继续使用以下数据集
要创建上述图形,请运行 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'}) | +------------------------------------------------------+
有关使用 |
如果您想更改 Jennifer 的出生日期,可以使用上述相同的查询再次找到 Jennifer 的节点,并在 SET
子句中输入不同的日期。
您还可以使用与更新节点类似的语法,更新 Jennifer 与 Company
节点的 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'}] | +-----------------------------------------+
如果您想在上述查询上返回图形视图,可以为 |
使用 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 语句来执行此操作
此语句不仅删除节点,还删除它所具有的所有关系。要运行此语句,您应该知道节点的内部 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 会使用您指定的 information 创建它。
在节点上使用 MERGE
首先,让我们通过以下查询将 Mark 添加回我们的数据库,以查看一个示例。您可以使用 MERGE
来确保 Cypher 检查数据库中是否已经存在 Mark 的节点。由于您在前面的示例中删除了 Mark 的节点,Cypher 不会找到现有匹配项,并将使用 name
属性设置为 'Mark' 的新节点创建节点。
MERGE (mark:Person {name: 'Mark'})
RETURN mark
查询结果
如果您再次运行相同的语句,Cypher 这次会找到一个现有节点,该节点的 name
属性设置为 Mark
,因此它将返回匹配的节点而不会进行任何更改。
在关系上使用 MERGE
就像您在 Cypher 中使用 MERGE
来查找或创建节点一样,您也可以使用它来查找或创建关系。让我们重新创建之前示例中 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
来查找 Mark 的节点和 Jennifer 的节点,然后使用 MERGE
来查找或创建它们之间的关系。
为什么我们不使用单一语句呢?
MERGE
会查找您指定的整个模式,以查看是返回现有模式还是创建新模式。如果整个模式(节点、关系和任何指定的属性)不存在,Cypher 将创建它。
Cypher 永远不会在一个模式内产生匹配和创建的局部混合。为了避免匹配和创建的混合,您需要首先匹配模式中任何现有的元素,然后才能对您可能想要创建的任何元素进行合并,就像我们在上面的语句中所做的那样。
仅供参考,导致重复的 Cypher 语句如下。由于此模式(
|
处理 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