COLLECT 子查询
COLLECT 子查询表达式可用于创建一个包含给定子查询所返回行的列表。
COLLECT 子查询与 COUNT 和 EXISTS 子查询的不同之处在于,其最终的 RETURN 子句是强制要求的。该 RETURN 子句必须且只能返回一列。
示例图
以下图表用于下方的示例
要重新创建该图,请在空的 Neo4j 数据库中运行以下查询
CREATE
(andy:Swedish:Person {name: 'Andy', age: 36}),
(timothy:Person {name: 'Timothy', nickname: 'Tim', age: 25}),
(peter:Person {name: 'Peter', nickname: 'Pete', age: 35}),
(andy)-[:HAS_DOG {since: 2016}]->(:Dog {name:'Andy'}),
(timothy)-[:HAS_CAT {since: 2019}]->(:Cat {name:'Mittens'}),
(fido:Dog {name:'Fido'})<-[:HAS_DOG {since: 2010}]-(peter)-[:HAS_DOG {since: 2018}]->(:Dog {name:'Ozzy'}),
(fido)-[:HAS_TOY]->(:Toy{name:'Banana'})
简单的 COLLECT 子查询
外部作用域引入的变量可以在 COLLECT 子查询中直接使用,无需导入。在这方面,COLLECT 子查询不同于 需要显式导入的 CALL 子查询。以下查询展示了这一点,并输出了名为 Ozzy 的狗的主人。
MATCH (person:Person)
WHERE 'Ozzy' IN COLLECT { MATCH (person)-[:HAS_DOG]->(dog:Dog) RETURN dog.name }
RETURN person.name AS name
| 名称 (name) |
|---|
|
行:1 |
带有 WHERE 子句的 COLLECT 子查询
WHERE 子句可以在 COLLECT 子查询内部使用。由 MATCH 子句和外部作用域引入的变量可以在内部作用域中使用。
MATCH (person:Person)
RETURN person.name as name, COLLECT {
MATCH (person)-[r:HAS_DOG]->(dog:Dog)
WHERE r.since > 2017
RETURN dog.name
} as youngDogs
| 名称 (name) | youngDogs |
|---|---|
|
|
|
|
|
|
行:3 |
|
条件 COLLECT 子查询仅限 Cypher 25Neo4j 2025.06 引入
WHEN 可在 COLLECT 子查询内使用,用于在谓词计算结果为 true 时有条件地执行分支。请注意,不同 WHEN 分支返回的列名和列数必须完全一致。有关更多信息,请参阅 条件查询 → 条件子查询。
在下面的查询示例中,如果某人有狗,则执行 WHEN 分支;如果某人没有狗,则执行 ELSE 分支。
COLLECT 子查询MATCH (n:Person)
RETURN n.name AS name,
COLLECT {
WHEN exists((n)-[:HAS_DOG]->(:Dog)) THEN {
RETURN 'Dog owner' AS petStatus
}
ELSE {
RETURN 'Cat owner' AS petStatus
}
} AS petStatus
| 名称 (name) | petStatus |
|---|---|
|
|
|
|
|
|
行:3 |
|
带有 UNION 的 COLLECT 子查询
COLLECT 可以与 UNION 子句结合使用。下面的示例展示了如何使用 UNION 子句来收集每个人拥有的宠物名称。
MATCH (person:Person)
RETURN
person.name AS name,
COLLECT {
MATCH (person)-[:HAS_DOG]->(dog:Dog)
RETURN dog.name AS petName
UNION
MATCH (person)-[:HAS_CAT]->(cat:Cat)
RETURN cat.name AS petName
} AS petNames
| 名称 (name) | petNames |
|---|---|
|
|
|
|
|
|
行:3 |
|
带有 WITH 的 COLLECT 子查询
外部作用域的变量在整个子查询中均可见,即使在使用 WITH 子句时也是如此。为避免混淆,不允许对这些变量进行遮蔽(shadowing)。当内部作用域中定义的变量与外部作用域变量同名时,就会发生变量遮蔽。在下面的示例中,外部变量 name 被遮蔽,因此会抛出错误。
WITH 'Peter' as name
MATCH (person:Person {name: name})
RETURN COLLECT {
WITH 'Ozzy' AS name
MATCH (person)-[r:HAS_DOG]->(d:Dog {name: name})
RETURN d.name
} as dogsOfTheYear
42N07: 错误: 语法错误或访问规则冲突 - 变量遮蔽。变量 42001:错误:语法错误或访问规则冲突 - 无效语法 |
只要使用不同的标识符,就可以在子查询中引入新变量。在下面的示例中,WITH 子句引入了一个新变量。请注意,主查询中引用的外部作用域变量 person 在 WITH 子句之后依然可用。
MATCH (person:Person)
RETURN person.name AS name, COLLECT {
WITH 2018 AS yearOfTheDog
MATCH (person)-[r:HAS_DOG]->(d:Dog)
WHERE r.since = yearOfTheDog
RETURN d.name
} as dogsOfTheYear
| 名称 (name) | dogsOfTheYear |
|---|---|
|
|
|
|
|
|
行:3 |
|
在其他子句中使用 COLLECT 子查询
COLLECT 可以用在查询中的任何位置,管理命令除外(在管理命令中 COLLECT 表达式受到限制)。以下是 COLLECT 在查询中不同位置使用方式的几个示例。
在 RETURN 中使用 COLLECT
MATCH (person:Person)
RETURN person.name,
COLLECT {
MATCH (person)-[:HAS_DOG]->(d:Dog)
MATCH (d)-[:HAS_TOY]->(t:Toy)
RETURN t.name
} as toyNames
| person.name | toyNames |
|---|---|
|
|
|
|
|
|
行:3 |
|
在 SET 中使用 COLLECT
MATCH (person:Person) WHERE person.name = "Peter"
SET person.dogNames = COLLECT { MATCH (person)-[:HAS_DOG]->(d:Dog) RETURN d.name }
RETURN person.dogNames as dogNames
| dogNames |
|---|
|
行:1 |
使用 COLLECT 与 collect() 的区别
COLLECT 处理 null 值的方式与聚合函数 collect() 不同。collect() 函数会自动移除 null 值。COLLECT 不会自动移除 null 值。不过,可以通过在子查询中添加过滤步骤来将其移除。
以下查询说明了这些区别:
MATCH (p:Person)
RETURN collect(p.nickname) AS names
| names |
|---|
|
行:1 |
RETURN COLLECT {
MATCH (p:Person)
RETURN p.nickname ORDER BY p.nickname
} AS names
| names |
|---|
|
行:1 |
RETURN COLLECT {
MATCH (p:Person)
WHERE p.nickname IS NOT NULL
RETURN p.nickname ORDER BY p.nickname
} AS names
| 名称 (name) |
|---|
|
行:1 |