WHERE

简介

WHERE 子句本身不是一个子句,而是MATCHOPTIONAL MATCHWITH 子句的一部分。

当与MATCHOPTIONAL MATCH 一起使用时,WHERE 会为描述的模式添加约束。它不应该被视为匹配完成后再进行的过滤器。

但在WITH 的情况下,WHERE 只是过滤结果。

在多个MATCH / OPTIONAL MATCH 子句的情况下,WHERE 中的谓词始终是紧接其前的MATCH / OPTIONAL MATCH 中模式的一部分。如果WHERE 放入错误的MATCH 子句中,则结果和性能都可能会受到影响。

索引 可用于在各种情况下优化使用WHERE 的查询。

示例图

以下图用于下面的示例

graph where clause

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

CREATE
(andy:Swedish:Person {name: 'Andy', age: 36, belt: 'white'}),
(timothy:Person {name: 'Timothy', age: 25}),
(peter:Person {name: 'Peter', age: 35, email: 'peter_n@example.com'}),
(andy)-[:KNOWS {since: 2012}]->(timothy),
(andy)-[:KNOWS {since: 1999}]->(peter)

基本用法

节点模式谓词

WHERE 可以出现在MATCH 子句或模式推导中的节点模式内

查询
WITH 30 AS minAge
MATCH (a:Person WHERE a.name = 'Andy')-[:KNOWS]->(b:Person WHERE b.age > minAge)
RETURN b.name
表 1. 结果
b.name

"Peter"

行数:1

当以这种方式使用时,WHERE 中的谓词可以引用WHERE 子句所属的节点变量,但不能引用MATCH 模式中的其他元素。

相同的规则适用于模式推导

查询
MATCH (a:Person {name: 'Andy'})
RETURN [(a)-->(b WHERE b:Person) | b.name] AS friends
表 2. 结果
friends

["Peter","Timothy"]

行数:1

布尔运算

以下布尔运算符可与WHERE 子句一起使用:ANDORXORNOT。有关运算符如何与null 一起工作的更多信息,请参阅有关使用 null 的章节。

查询
MATCH (n:Person)
WHERE n.name = 'Peter' XOR (n.age < 30 AND n.name = 'Timothy') OR NOT (n.name = 'Timothy' OR n.name = 'Peter')
RETURN
  n.name AS name,
  n.age AS age
ORDER BY name
表 3. 结果
name age

"Andy"

36

"Peter"

35

"Timothy"

25

行数:3

根据节点标签过滤

要根据标签过滤节点,请使用WHERE n:fooWHERE 关键字后编写标签谓词

查询
MATCH (n)
WHERE n:Swedish
RETURN n.name, n.age

返回Andynameage

表 4. 结果
n.name n.age

"Andy"

36

行数:1

根据节点属性过滤

要根据节点属性进行过滤,请在WHERE 关键字后编写您的子句

查询
MATCH (n:Person)
WHERE n.age < 30
RETURN n.name, n.age

返回Timothynameage 值,因为他不到 30 岁

表 5. 结果
n.name n.age

"Timothy"

25

行数:1

根据关系属性过滤

要根据关系属性进行过滤,请在WHERE 关键字后编写您的子句

查询
MATCH (n:Person)-[k:KNOWS]->(f)
WHERE k.since < 2000
RETURN f.name, f.age, f.email

返回Peternameageemail 值,因为Andy 从 2000 年之前就认识他了

表 6. 结果
f.name f.age f.email

"Peter"

35

"peter_n@example.com"

行数:1

根据动态计算的节点属性过滤

要使用动态计算的名称过滤属性,请使用方括号语法

查询
WITH 'AGE' AS propname
MATCH (n:Person)
WHERE n[toLower(propname)] < 30
RETURN n.name, n.age

返回Timothynameage 值,因为他不到 30 岁

表 7. 结果
n.name n.age

"Timothy"

25

行数:1

属性存在性检查

使用IS NOT NULL 谓词仅包含存在属性的节点或关系

查询
MATCH (n:Person)
WHERE n.belt IS NOT NULL
RETURN n.name, n.belt

返回Andynamebelt 值,因为他唯一一个具有belt 属性的人

表 8. 结果
n.name n.belt

"Andy"

"white"

行数:1

使用WITH

由于WHERE 不被视为一个子句,因此它的范围不受其之前的WITH 的限制。

查询
MATCH (n:Person)
WITH n.name as name
WHERE n.age = 25
RETURN name
表 9. 结果
name

"Timothy"

行数:1

由于WHERE子句仍然充当对MATCH的过滤器,因此返回了Timothy的名字。WITH缩小了后续查询的范围。在本例中,name现在是RETURN子句中唯一的有效变量。

STRING匹配

可以使用STARTS WITHENDS WITH匹配STRING的前缀和后缀。要进行子字符串搜索(即,无论在STRING中的位置如何都匹配),请使用CONTAINS

匹配是区分大小写的。尝试对不是STRING值的值使用这些运算符将返回null

使用STARTS WITH进行前缀STRING搜索

STARTS WITH运算符用于对STRING的开头执行区分大小写的匹配

查询
MATCH (n:Person)
WHERE n.name STARTS WITH 'Pet'
RETURN n.name, n.age

返回Peternameage值,因为他的名字以“Pet”开头。

表 10. 结果
n.name n.age

"Peter"

35

行数:1

使用ENDS WITH进行后缀STRING搜索

ENDS WITH运算符用于对STRING的结尾执行区分大小写的匹配

查询
MATCH (n:Person)
WHERE n.name ENDS WITH 'ter'
RETURN n.name, n.age

返回Peternameage值,因为他的名字以“ter”结尾。

表 11. 结果
n.name n.age

"Peter"

35

行数:1

使用CONTAINS进行子字符串搜索

CONTAINS运算符用于执行区分大小写的匹配,而不管在STRING中的位置如何

查询
MATCH (n:Person)
WHERE n.name CONTAINS 'ete'
RETURN n.name, n.age

返回Peternameage,因为他的名字包含“ete”。

表 12. 结果
n.name n.age

"Peter"

35

行数:1

检查STRING是否IS NORMALIZED

IS NORMALIZED运算符(在 Neo4j 5.17 中引入)用于检查给定的STRING是否为NFC Unicode 规范化形式。

查询
MATCH (n:Person)
WHERE n.name IS NORMALIZED
RETURN n.name AS normalizedNames

给定的STRING值仅包含规范化的 Unicode 字符,因此返回所有匹配的name属性。有关更多信息,请参阅有关规范化运算符的部分。

表 13. 结果
normalizedNames

'Andy'

'Timothy'

'Peter'

请注意,当对非STRING值使用IS NORMALIZED运算符时,它将返回null。例如,RETURN 1 IS NORMALIZED返回null

字符串匹配否定

使用NOT关键字从结果中排除所有给定STRING上的匹配项。

查询
MATCH (n:Person)
WHERE NOT n.name ENDS WITH 'y'
RETURN n.name, n.age

返回Peternameage值,因为他的名字不以“y”结尾。

表 14. 结果
n.name n.age

"Peter"

35

行数:1

正则表达式

Cypher®支持使用正则表达式进行过滤。正则表达式语法继承自Java 正则表达式。这包括支持更改STRING值匹配方式的标志,包括不区分大小写的(?i)、多行(?m)和点号匹配所有字符(?s)

标志位于正则表达式的开头。有关在模式开头给出的正则表达式标志的示例,请参阅不区分大小写的正则表达式部分。

使用正则表达式匹配

要根据正则表达式进行匹配,请使用=~ 'regexp'

查询
MATCH (n:Person)
WHERE n.name =~ 'Tim.*'
RETURN n.name, n.age

返回Timothynameage值,因为他的名字以“Tim”开头。

表 15. 结果
n.name n.age

"Timothy"

25

行数:1

正则表达式中的转义

.*这样的字符在正则表达式中具有特殊含义。要将它们用作普通字符,而没有特殊含义,请对其进行转义。

查询
MATCH (n:Person)
WHERE n.email =~ '.*\\.com'
RETURN n.name, n.age, n.email

返回Peternameageemail值,因为他的电子邮件以“.com”结尾。

表 16. 结果
n.name n.age n.email

"Peter"

35

"peter_n@example.com"

行数:1

请注意,Java 正则表达式中的正则表达式构造仅在解析给定字符串文字中的转义字符序列后应用。有时需要添加额外的反斜杠来表达正则表达式构造。此列表阐明了这两个定义的组合,其中包含原始转义序列和正则表达式中的结果字符。

字符串文字序列 结果正则表达式序列 正则表达式匹配

\t

制表符

制表符

\\t

\t

制表符

\b

退格键

退格键

\\b

\b

单词边界

\n

换行符

NewLine

\\n

\n

换行符

\r

回车符

回车符

\\r

\r

回车符

\f

换页符

换页符

\\f

\f

换页符

\'

单引号

单引号

\"

双引号

双引号

\\

反斜杠

反斜杠

\\\

\\

反斜杠

\uxxxx

Unicode UTF-16 代码点(\u后必须跟随 4 个十六进制数字)

Unicode UTF-16 代码点(\u后必须跟随 4 个十六进制数字)

\\uxxxx

\uxxxx

Unicode UTF-16 代码点(\u后必须跟随 4 个十六进制数字)

使用未经消毒的用户输入的正则表达式会使您容易受到 Cypher 注入的攻击。请考虑改用参数

不区分大小写的正则表达式

通过在正则表达式前面加上(?i),整个表达式将变得不区分大小写。

查询
MATCH (n:Person)
WHERE n.name =~ '(?i)AND.*'
RETURN n.name, n.age

返回Andynameage,因为无论大小写如何,他的名字都以“AND”开头。

表 17. 结果
n.name n.age

"Andy"

36

行数:1

路径模式表达式

存在子查询类似,路径模式表达式可用于断言指定路径在图中是否存在至少一次。虽然存在子查询功能更强大,并且能够执行路径模式表达式所能实现的任何操作,但路径模式表达式更简洁。

路径模式表达式具有以下限制(需要扩展功能的用例应考虑改用存在子查询)。

  • 路径模式表达式只能使用图模式语义的一个子集。

  • 路径模式表达式必须是长度大于零的路径模式。换句话说,它必须包含至少一个关系可变长度关系

  • 路径模式表达式不能声明新变量。它们只能引用现有变量。

  • 路径模式表达式只能用于期望布尔表达式的位置。以下部分将演示如何在WHERE子句中使用路径模式表达式。

根据模式过滤

查询
MATCH
  (timothy:Person {name: 'Timothy'}),
  (other:Person)
WHERE (other)-->(timothy)
RETURN other.name, other.age

返回具有到Timothy的出站关系的节点的nameage值。

表 18. 结果
other.name other.age

"Andy"

36

行数:1

使用NOT根据模式过滤

NOT运算符可用于排除模式。

查询
MATCH
  (peter:Person {name: 'Peter'}),
  (other:Person)
WHERE NOT (other)-->(peter)
RETURN other.name, other.age

返回没有到Peter的出站关系的节点的nameage值。

表 19. 结果
other.name other.age

"Timothy"

25

"Peter"

35

行数:2

根据具有属性的模式过滤

属性也可以添加到模式中。

查询
MATCH (other:Person)
WHERE (other)-[:KNOWS]-({name: 'Timothy'})
RETURN other.name, other.age

返回具有类型为KNOWS并连接到Timothy的关系的节点的nameage值。

表 20. 结果
other.name other.age

"Andy"

36

行数:1

列表

IN运算符

要检查列表中是否存在元素,请使用IN运算符。以下查询检查属性是否存在于文字列表中。

查询
MATCH (a:Person)
WHERE a.name IN ['Peter', 'Timothy']
RETURN a.name, a.age
表 21. 结果
a.name a.age

"Timothy"

25

"Peter"

35

行数:2

缺少属性和值

如果属性丢失,则默认为false

由于缺少的属性计算为null,因此示例中的比较对于没有belt属性的节点将计算为false

查询
MATCH (n:Person)
WHERE n.belt = 'white'
RETURN n.name, n.age, n.belt

仅返回具有白色腰带的节点的nameagebelt值。

表 22. 结果
n.name n.age n.belt

"Andy"

36

"white"

行数:1

如果属性丢失,则默认为true

要将节点或关系属性与缺少的属性进行比较,请使用IS NULL运算符。

查询
MATCH (n:Person)
WHERE n.belt = 'white' OR n.belt IS NULL
RETURN n.name, n.age, n.belt
ORDER BY n.name

这将返回所有节点的所有值,即使是那些没有belt属性的节点。

表 23. 结果
n.name n.age n.belt

"Andy"

36

"white"

"Peter"

35

<null>

"Timothy"

25

<null>

行数:3

根据null过滤

要测试值或变量是否为null,请使用IS NULL运算符。要测试值或变量是否不为null,请使用IS NOT NULL运算符,NOT(IS NULL x)也有效。

查询
MATCH (person:Person)
WHERE person.name = 'Peter' AND person.belt IS NULL
RETURN person.name, person.age, person.belt

返回名称为Peter但没有belt属性的节点的nameage值。

表 24. 结果
person.name person.age person.belt

"Peter"

35

<null>

行数:1

使用范围

简单范围

要检查元素是否存在于特定范围内,请使用不等式运算符<>=>

查询
MATCH (a:Person)
WHERE a.name >= 'Peter'
RETURN a.name, a.age

返回name属性按字典顺序(即使用字典顺序)大于或等于Peter的节点的nameage值。

表 25. 结果
a.name a.age

"Timothy"

25

"Peter"

35

行数:2

复合范围

可以使用多个不等式来构造范围。

查询
MATCH (a:Person)
WHERE a.name > 'Andy' AND a.name < 'Timothy'
RETURN a.name, a.age

返回name属性按字典顺序介于AndyTimothy之间的节点的nameage值。

表 26. 结果
a.name a.age

"Peter"

35

行数:1

模式元素谓词

可以将WHERE子句添加到模式元素以指定其他约束。

关系模式谓词

WHERE也可以出现在MATCH子句中的关系模式内部。

查询
WITH 2000 AS minYear
MATCH (a:Person)-[r:KNOWS WHERE r.since < minYear]->(b:Person)
RETURN r.since
表 27. 结果
r.since

1999

行数:1

但是,它不能用于可变长度关系中,因为这会导致错误。例如

查询
WITH 2000 AS minYear
MATCH (a:Person)-[r:KNOWS*1..3 WHERE r.since > b.yearOfBirth]->(b:Person)
RETURN r.since
错误消息
Relationship pattern predicates are not supported for variable-length relationships.

将谓词放在关系模式内可以提高可读性。请注意,这与使用独立的WHERE子句严格等价。

查询
WITH 2000 AS minYear
MATCH (a:Person)-[r:KNOWS]->(b:Person)
WHERE r.since < minYear
RETURN r.since
表 28. 结果
r.since

1999

行数:1

关系模式谓词也可以用在模式推导中,同样适用上述注意事项。

查询
WITH 2000 AS minYear
MATCH (a:Person {name: 'Andy'})
RETURN [(a)-[r:KNOWS WHERE r.since < minYear]->(b:Person) | r.since] AS years
表 29. 结果
年份

[1999]

行数:1