目录

Cypher 查询语言的增删改查

主要学习资源有:

关键字

要想在 Neo4j 中增删改查,有几个关键字需要整明白。

  • MATCH1:类似SELECT,查询存在的节点、边、标签、属性、模式等。
  • RETURN2:指定从查询语句中返回的结果,可以返回节点、边、属性、模式等。要想返回,你需要在 MATCH 子句中使用变量。
  • AS:对返回的变量赋予别名。
  • CREATE3:类似INSERT,插入节点、边、模式。盲插,无论存不存在,可能造成重复插入。
  • SET4:修改节点或边的属性,可增、删、改。可添加日期时间类型5的数据。第一次设置则为添加,第二/n次设置则为修改,设置为 null 则是删除属性(也可以用 REMOVE 6删除特定属性)。
  • DELETE7:删除节点、边。删除边需要先找到这条边。删除没有边连接的节点需要先找到这个节点。删除有边连接的节点,你可以分成两个步骤先删除边然后删除节点,也可以使用 DETACH DELETE 删除所有与节点相连的边之后删除节点。
  • MERGE8:先查找再操作,如果没有则添加。如果此次操作是新建ON CREATE9,如果此次操作是匹配 ON MATCH

// 添加一个类型为 Person 的节点,并用 friend 引用,然后返回结果
CREATE (friend:Person {name: 'Mark'})
RETURN friend

// 找到两个节点,并为它俩添加一条边
MATCH (jennifer:Person {name: 'Jennifer'})
MATCH (mark:Person {name: 'Mark'})
CREATE (jennifer)-[rel:IS_FRIENDS_WITH]->(mark)

// 创建两个节点,并为这两个节点连接一条边。这会重复添加!
CREATE (j:Person {name: 'Jennifer'})-[rel:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})

// 找到一个节点,并添加一条属性,使用变量 p 引用这个节点,然后返回结果。重复使用该语句会更新属性,而不是重复添加。
MATCH (p:Person {name: 'Jennifer'})
SET p.birthdate = date('1980-01-01')  // 这里使用了 date 函数
RETURN p

// 找到一条边,并删除这条边
MATCH (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
DELETE r

// 删除一个节点,这个节点没有任何边与之相联
MATCH (m:Person {name: 'Mark'})
DELETE m

// 找到一个节点,并删除这个节点及其所有边
MATCH (m:Person {name: 'Mark'})
DETACH DELETE m

//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 n.birthdate = null,为什么这么做行?我们知道关系型数据库中这样做是把该字段的值置为 null ,而图数据库呢?图数据库只存储对数据有意义的属性和值,这意味着节点和边可有不同类型和不同数量的属性10

// 找到一条边,并用变量 rel 引用,然后修改 rel 边的属性,最后返回这条边(只会显示属性),如果要显示节点,则需要返回 p,rel,c
MATCH (:Person {name: 'Jennifer'})-[rel:WORKS_FOR]-(:Company {name: 'Neo4j'})
SET rel.startYear = date({year: 2018})
RETURN rel

// 返回一个 Person 节点
MATCH (p:Person)
RETURN p
LIMIT 1

// 返回所有的具有 name为'Tom Hanks' 属性的 Persion 节点
MATCH (tom:Person {name: 'Tom Hanks'})
RETURN tom
                    
// 返回所有的 Tom Hanks 执导的电影名称
MATCH (:Person {name: 'Tom Hanks'})-[:DIRECTED]->(movie:Movie)
RETURN movie.tilte

// cleaner printed results with aliasing
MATCH (tom:Person {name:'Tom Hanks'})-[rel:DIRECTED]-(movie:Movie)
RETURN tom.name AS name, tom.born AS `Year Born`, movie.title AS title, movie.released AS `Year Released`

避免重复数据

之前用 CREATE 的时候可能产生重复数据,解决的办法之一是使用 MERGE

MERGE 做的是 select or insert 的事,它首先检索数据存在与否,如果存在则直接返回(或直接做修改),否则先创建数据。

// 查找一个节点,如果不存在则插入
MERGE (mark:Person {name: 'Mark'})
RETURN mark

// 查找一条边,如果不存在则插入
MATCH (j:Person {name: 'Jennifer'})
MATCH (m:Person {name: 'Mark'})
MERGE (j)-[r:IS_FRIENDS_WITH]->(m)  // 为什么只在这里使用 MERGE ?
RETURN j, r, m

// 以下语句,会创建重复的两个节点!
MERGE (j:Person {name: 'Jennifer'})-[r:IS_FRIENDS_WITH]->(m:Person {name: 'Mark'})
RETURN j, r, m

// 如果新建模式则设置 since 属性,如果匹配模式则修改 updated 属性
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

MERGE 会查找整个 Pattern 模式存不存在,如果模式不存在(包括节点、边、属性),就会新建10。 所以,你需要先查找已经存在的数据,然后使用 MERGE 来创建你可能会创建的数据。 也许,你想在新建模式的时候初始化一些属性,,或者想匹配模式的时候修改一些属性,那么在这种情况下,可使用 ON CREATEON MATECH 结合 SET。【如果创建了模式,您想初始化某些属性,如果仅匹配,则更新其他属性】