SET

SET 子句用于更新节点上的标签以及节点和关系上的属性。

SET 子句可以与映射(以字面量或参数形式提供)一起使用,以设置属性。

在节点上设置标签是幂等操作——如果尝试在一个已经拥有该标签的节点上设置标签,则不会发生任何事情。查询统计信息将说明是否实际发生了任何更新。

示例图

以下图用于下面的示例

[width="500"

要重新创建它,请在空的 Neo4j 数据库上运行以下查询

CREATE
  (a:Swedish {name: 'Andy', age: 36, hungry: true}),
  (b {name: 'Stefan'}),
  (c {name: 'Peter', age: 34}),
  (d {name: 'George'}),
  (a)-[:KNOWS]->(c),
  (b)-[:KNOWS]->(a),
  (d)-[:KNOWS]->(c)

设置属性

更新节点属性

查询
MATCH (n {name: 'Andy'})
SET n.surname = 'Taylor'
RETURN n.name, n.surname

查询返回新更改的节点。

表 1. 结果
n.name n.surname

"Andy"

"Taylor"

行数: 1
已设置属性: 1

更新关系属性

查询
MATCH (n:Swedish {name: 'Andy'})-[r:KNOWS]->(m)
SET r.since = 1999
RETURN r, m.name AS friend
表 2. 结果
r 朋友

[:KNOWS {since: 1999}]

"Peter"

行数: 1
已设置属性: 1

可以使用更复杂的表达式在节点或关系上设置属性。例如,与直接指定节点不同,以下查询显示了如何为通过表达式选择的节点设置属性

查询
MATCH (n {name: 'Andy'})
SET (CASE WHEN n.age = 36 THEN n END).worksIn = 'Malmo'
RETURN n.name, n.worksIn
表 3. 结果
n.name n.worksIn

"Andy"

"Malmo"

行数: 1
已设置属性: 1

如果节点表达式评估为 null,则不会采取任何操作,示例如下

查询
MATCH (n {name: 'Andy'})
SET (CASE WHEN n.age = 55 THEN n END).worksIn = 'Malmo'
RETURN n.name, n.worksIn

由于没有节点匹配 CASE 表达式,该表达式返回 null。因此,没有发生更新,也没有设置 worksIn 属性。

表 4. 结果
n.name n.worksIn

"Andy"

<null>

行数: 1

更新属性

SET 可用于更新节点或关系上的属性。此查询强制更改 age 属性的类型

查询
MATCH (n {name: 'Andy'})
SET n.age = toString(n.age)
RETURN n.name, n.age

age 属性已转换为 STRING '36'

表 5. 结果
n.name n.age

"Andy"

"36"

行数: 1
已设置属性: 1

动态设置或更新属性

SET 可用于在节点或关系上设置或更新属性,即使属性键名不是静态已知的。这允许更灵活的查询并降低 Cypher® 注入的风险。(有关 Cypher 注入的更多信息,请参阅 Neo4j 知识库 → 防范 Cypher 注入)。

SET n[key] = expression

动态计算的键必须评估为 STRING 值。此查询为节点上的每个属性创建副本

查询
MATCH (n)
FOREACH (k IN keys(n) | SET n[k + "Copy"] = n[k]) (1)
RETURN n.name, keys(n);
1 FOREACH 子句迭代从 keys() 函数获取的每个属性键 k。对于每个键,它在节点上设置一个新属性,其键名为 k + "Copy",并从原始属性复制值。

节点现在拥有其所有属性的副本。

表 6. 结果
n.name keys(n)

"Andy"

["name", "nameCopy", "age", "ageCopy", "hungry", "hungryCopy"]

"Stefan"

["name", "nameCopy"]

"Peter"

["name", "nameCopy", "age", "ageCopy"]

"George"

["name", "nameCopy"]

行数: 4
已设置属性: 6

移除属性

虽然 REMOVE 通常用于移除属性,但有时使用 SET 命令来完成此操作会很方便。一个典型例子是当属性由参数提供时。

查询
MATCH (n {name: 'Andy'})
SET n.name = null
RETURN n.name, n.age

name 属性现在缺失。

表 7. 结果
n.name n.age

<null>

"36"

行数: 1
已设置属性: 1

在节点和关系之间复制属性

SET 可用于使用 properties() 函数将所有属性从一个节点或关系复制到另一个节点或关系。这将移除被复制到的节点或关系上的所有其他属性。

查询
MATCH
  (at {name: 'Andy'}),
  (pn {name: 'Peter'})
SET at = properties(pn)
RETURN at.name, at.age, at.hungry, pn.name, pn.age

'Andy' 节点的所有属性已被 'Peter' 节点的属性替换。

表 8. 结果
at.name at.age at.hungry pn.name pn.age

"Peter"

34

<null>

"Peter"

34

行数: 1
已设置属性: 3

使用映射和 = 替换所有属性

属性替换操作符 = 可与 SET 一起使用,以将节点或关系上的所有现有属性替换为映射提供的属性

查询
MATCH (p {name: 'Peter'})
SET p = {name: 'Peter Smith', position: 'Entrepreneur'}
RETURN p.name, p.age, p.position

此查询将 name 属性从 Peter 更新为 Peter Smith,删除了 age 属性,并将 position 属性添加到 'Peter' 节点。

表 9. 结果
p.name p.age p.position

"Peter Smith"

<null>

"企业家"

行数: 1
已设置属性: 3

使用空映射和 = 移除所有属性

通过使用 SET= 并将空映射作为右操作数,可以从节点或关系中移除所有现有属性

查询
MATCH (p {name: 'Peter'})
SET p = {}
RETURN p.name, p.age

此查询从 'Peter' 节点中移除了所有现有属性——即 nameage

表 10. 结果
p.name p.age

<null>

<null>

行数: 1
已设置属性: 2

使用映射和 += 更改特定属性

属性更改操作符 += 可与 SET 一起使用,以精细地更改映射中的属性

  • 映射中不在节点或关系上的任何属性都将添加

  • 映射中不在节点或关系上的任何属性将保持不变。

  • 同时存在于映射和节点或关系中的任何属性都将在节点或关系中被替换。但是,如果映射中的任何属性为 null,它将从节点或关系中被移除

查询
MATCH (p {name: 'Peter'})
SET p += {age: 38, hungry: true, position: 'Entrepreneur'}
RETURN p.name, p.age, p.hungry, p.position

此查询使 name 属性保持不变,将 age 属性从 34 更新为 38,并将 hungryposition 属性添加到 'Peter' 节点。

表 11. 结果
p.name p.age p.hungry p.position

"Peter"

38

true

"企业家"

行数: 1
已设置属性: 3

与属性替换操作符 = 相反,将空映射作为右操作数提供给 += 不会从节点或关系中移除任何现有属性。根据上面详述的语义,传入带有 += 的空映射将不起作用

查询
MATCH (p {name: 'Peter'})
SET p += {}
RETURN p.name, p.age
表 12. 结果
p.name p.age

"Peter"

34

行数: 1

使用一个 SET 子句设置多个属性

通过逗号分隔一次设置多个属性

查询
MATCH (n {name: 'Andy'})
SET n.position = 'Developer', n.surname = 'Taylor'
表 13. 结果

(空结果)

行数: 0
已设置属性: 2

使用参数设置属性

使用参数设置属性值

参数
{
  "surname": "Taylor"
}
查询
MATCH (n {name: 'Andy'})
SET n.surname = $surname
RETURN n.name, n.surname

'Andy' 节点已添加 surname 属性。

表 14. 结果
n.name n.surname

"Andy"

"Taylor"

行数: 1
已设置属性: 1

使用参数设置所有属性

这将用参数提供的新属性集替换节点上的所有现有属性。

参数
{
  "props" : {
    "name": "Andy",
    "position": "Developer"
  }
}
查询
MATCH (n {name: 'Andy'})
SET n = $props
RETURN n.name, n.position, n.age, n.hungry

'Andy' 节点的所有属性已被 props 参数中的属性替换。

表 15. 结果
n.name n.position n.age n.hungry

"Andy"

"开发者"

<null>

<null>

行数: 1
已设置属性: 4

在节点上设置标签

使用 SET 在节点上设置标签

查询
MATCH (n {name: 'Stefan'})
SET n:German
RETURN n.name, labels(n) AS labels

查询返回新标记的节点。

表 16. 结果
n.name labels

"Stefan"

["German"]

行数: 1
已添加标签: 1

动态设置节点标签

SET 可用于在节点上设置标签,即使标签不是静态已知的。

MATCH (n)
SET n:$(<expr>)
查询
MATCH (n:Swedish)
SET n:$(n.name)
RETURN n.name, labels(n) AS labels

查询返回新标记的节点。

表 17. 结果
n.name labels

"Andy"

["Swedish", "Andy"]

行数: 1
已添加标签: 1

使用参数设置标签

使用参数设置标签值

参数
{
  "label": "Danish"
}
查询
MATCH (n {name: 'Stefan'})
SET n:$($label)
RETURN labels(n) AS labels

'Stefan' 节点已添加 Danish 标签。

表 18. 结果
labels

['German', 'Danish']

行数: 1
已添加标签: 1

在节点上设置多个标签

使用 SET 在节点上设置多个标签,并使用 : 分隔不同的标签

查询
MATCH (n {name: 'George'})
SET n:Swedish:Bossman
RETURN n.name, labels(n) AS labels

查询返回新标记的节点。

表 19. 结果
n.name labels

"George"

["Swedish","Bossman"]

行数: 1
已添加标签: 2

在节点上动态设置多个标签

可以使用 LIST<STRING> 动态设置多个标签,和/或通过 : 单独链接它们

查询
WITH COLLECT { UNWIND range(0,3) AS id RETURN "Label" + id } as labels (1)
MATCH (n {name: 'George'})
SET n:$(labels)
RETURN n.name, labels(n) AS labels
1 一个 COLLECT 子查询聚合了 UNWIND range(0,3) AS id RETURN "Label" + id 的结果,该结果生成一个 LIST<STRING> 字符串列表("Label0", "Label1", "Label2", "Label3"),并将其赋值给变量 labels

查询返回新标记的节点。

表 20. 结果
n.name labels

"George"

["Swedish","Bossman", "Label0", "Label1", "Label2", "Label3"]

行数: 1
已添加标签: 4

使用参数设置多个标签

使用参数设置多个标签

参数
{
  "labels": ["Swedish", "German"]
}
查询
MATCH (n {name: 'Peter'})
SET n:$($labels)
RETURN labels(n) AS labels

'Peter' 节点已添加 SwedishGerman 标签。

表 21. 结果
labels

['Swedish', 'German']

行数: 1
已添加标签: 2