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 friend

[: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 可用于设置或更新节点或关系上的属性,即使属性键名称不是静态已知的。

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>

"Entrepreneur"

行数: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

"Entrepreneur"

行数: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

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

表 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"

"Developer"

<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

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

表 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

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

表 21. 结果
labels

['Swedish', 'German']

行数:1
添加的标签: 2