前言
前面你学习了如何在Cypher中表示节点、关系、标签、属性和模式。本节通过介绍如何用Cypher更新和删除数据为你的知识增加了一个层次。
虽然这些是标准的CRUD(创建、更新和删除)操作,但有些东西在图中的功能与其他类型的数据库有点不同。在我们进行的过程中,你可能会认识到一些相似和不同之处。
1. 用Cypher更新数据
你可能已经在数据中拥有一个节点或关系,但你想修改它的属性。你可以通过MATCH你想找到的模式并使用SET关键字来添加、删除或更新属性来做到这一点。
到目前为止,使用上面的例子数据集,你可以更新Jennifer的节点,增加她的出生日期。接下来的Cypher语句显示了如何做到这一点。
-
首先,你需要找到Jennifer的现有节点。
-
接下来,使用SET来创建新的属性(语法为variable.property)并设置其值。
-
最后,你可以返回Jennifer的节点以确保信息被正确更新。
MATCH (p:Person {name: 'Jennifer'})
SET p.birthdate = date('1980-01-01')
RETURN p
如果你想改变Jennifer的出生日期,你可以使用上述相同的查询,再次找到Jennifer的节点,并在SET子句中放入不同的日期。
你还可以更新Jennifer与公司节点的WORKS_FOR关系,以包括她开始在那里工作的年份。要做到这一点,你可以使用与上面类似的语法来更新节点。
MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'})
SET rel.startYear = date({year: 2018})
RETURN rel
2. 用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
删除一个节点
要删除一个没有任何关系的节点,你需要找到你想删除的节点,然后使用DELETE关键字,就像你对上面的关系一样。你可以暂时删除马克的节点,以后再把他带回来。
MATCH (m:Person {name: 'Mark'})
DELETE m
删除一个节点和它的关系
与其运行最后两个查询来删除IS_FRIENDS_WITH关系和Mark的Person节点,你实际上可以运行一个语句来同时删除节点和其关系。正如上面提到的,Neo4j是符合ACID标准的,所以它不允许删除一个仍有关系的节点。使用DETACH DELETE语法告诉Cypher删除该节点的任何关系,以及删除该节点本身。
该语句看起来就像下面的代码。首先,你在数据库中找到马克的节点。然后,DETACH DELETE行删除马克节点的任何现有关系,然后再删除该节点。
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
3. 使用MERGE避免重复的数据
前面简单提到,在Cypher中,有一些方法可以避免创建重复的数据。其中一个方法是使用MERGE关键字。MERGE做了一个 "选择或插入 "操作,首先检查数据是否存在于数据库中。如果它存在,那么Cypher将其原样返回,或者在现有的节点或关系上做任何你指定的更新。如果数据不存在,那么Cypher将用你指定的信息创建它。
在一个节点上使用MERGE
首先,让我们看一个例子,用下面的查询把马克加回到我们的数据库中。你可以使用MERGE来确保Cypher检查数据库中是否有Mark的现有节点。由于你在前面的例子中删除了Mark的节点,Cypher将不会找到现有的匹配,并将创建新的节点,其名称属性设置为’Mark’。
MERGE (mark:Person {name: 'Mark'})
RETURN mark
4. UNION
如果你想把两个具有相同结果结构的语句的结果结合起来,你可以使用UNION [ALL]。
例如,下面的语句同时列出了演员和导演。
MATCH (actor:Person)-[r:ACTED_IN]->(movie:Movie)
RETURN actor.name AS name, type(r) AS type, movie.title AS title
UNION
MATCH (director:Person)-[r:DIRECTED]->(movie:Movie)
RETURN director.name AS name, type(r) AS type, movie.title AS title
WITH
在Cypher中,你可以将语句的片段连锁起来,类似于数据流管道中的做法。每个片段都在前一个片段的输出上工作,其结果可以反馈到下一个片段。只有在WITH子句中声明的列才能在后续的查询部分中使用。
WITH子句被用来结合各个部分,并声明哪些数据从一个部分流向另一个部分。WITH与RETURN子句类似。不同的是,WITH子句并没有完成查询,而是为下一个部分的输入做准备。表达式、聚合、排序和分页的使用方法与RETURN子句相同。唯一的区别是所有的列都必须是别名。
在下面的例子中,收集某人出现的电影,然后过滤掉那些只出现在一部电影中的电影。
MATCH (person:Person)-[:ACTED_IN]->(m:Movie)
WITH person, count(*) AS appearances, collect(m.title) AS movies
WHERE appearances > 1
RETURN person.name, appearances, movies