https://neo4j.com/docs/cypher-manual/current/clauses/optional-match/
OPTIONAL MATCH
Introduction
OPTIONAL MATCH
matches patterns against a graph database, just as MATCH
does. The difference is that if no matches are found, OPTIONAL MATCH
will use a null
for missing parts of the pattern. OPTIONAL MATCH
could therefore be considered the Cypher® equivalent of the outer join in SQL.
When using OPTIONAL MATCH
, either the whole pattern is matched, or nothing is matched. The WHERE
clause is part of the pattern description, and its predicates will be considered while looking for matches, not after. This matters especially in the case of multiple (OPTIONAL
) MATCH
clauses, where it is crucial to put WHERE
together with the MATCH
it belongs to.
To understand the patterns used in the |
OPTIONAL MATCH
就像将模式与图形数据库进行匹配一样MATCH
。不同之处在于,如果未找到匹配项,OPTIONAL MATCH
将使用 null
来表示模式中缺失的部分。 OPTIONAL MATCH
因此,可以将 Cypher ®视为SQL 中外连接的等价物。
使用 时OPTIONAL MATCH
,要么匹配整个模式,要么不匹配任何内容。该WHERE
子句是模式描述的一部分,其谓词将在查找匹配时而不是之后考虑。OPTIONAL
这在有多个 ( )子句的情况下尤其重要,将其与其所属的MATCH
放在一起至关重要。
Example graph
The following graph is used for the examples below:
To recreate the graph, run the following query in an empty Neo4j database:
CREATE
(charlie:Person {name: 'Charlie Sheen'}),
(martin:Person {name: 'Martin Sheen'}),
(michael:Person {name: 'Michael Douglas'}),
(oliver:Person {name: 'Oliver Stone'}),
(rob:Person {name: 'Rob Reiner'}),
(wallStreet:Movie {title: 'Wall Street'}),
(charlie)-[:ACTED_IN]->(wallStreet),
(martin)-[:ACTED_IN]->(wallStreet),
(michael)-[:ACTED_IN]->(wallStreet),
(oliver)-[:DIRECTED]->(wallStreet),
(thePresident:Movie {title: 'The American President'}),
(martin)-[:ACTED_IN]->(thePresident),
(michael)-[:ACTED_IN]->(thePresident),
(rob)-[:DIRECTED]->(thePresident),
(martin)-[:FATHER_OF]->(charlie)
OPTIONAL MATCH in more detail
Like SQL, Cypher queries are constructed using various clauses which are chained together to feed intermediate results between each other. For example, the matching variables from one MATCH
clause will provide the context in which the next clause exists. However, there are two important differences between Neo4j and SQL which helps to explain OPTIONAL MATCH
further.
-
While it is both possible and advised to enforce partial schemas using indexes and constraints, Neo4j offers a greater degree of schema flexibility than a relational database. Nodes and relationships in a Neo4j database do not have to have a specific property set to them because other nodes or relationships in the same graph have that property (unless there is a existence constraint created on the specific property).
-
Queries in Cypher are run as pipelines. If a clause returns no results, it will effectively end the query as subsequent clauses will have no data to execute upon.
For example, the following query returns no results:
与 SQL 一样,Cypher 查询是使用各种子句构建的,这些子句链接在一起以在彼此之间提供中间结果。例如,一个MATCH
子句中的匹配变量将提供下一个子句存在的上下文。然而,Neo4j 和 SQL 之间有两个重要的区别,这有助于OPTIONAL MATCH
进一步解释。
-
虽然可以并且建议使用索引和约束来强制执行部分模式,但 Neo4j 提供了比关系数据库更大程度的模式灵活性。Neo4j 数据库中的节点和关系不必设置特定的属性,因为同一图中的其他节点或关系具有该属性(除非在特定属性上创建了存在约束)。
-
Cypher 中的查询作为管道运行。如果一个子句没有返回结果,它将有效地结束查询,因为后续子句将没有数据可执行。
例如,以下查询不返回结果:
MATCH (a:Person {name: 'Martin Sheen'})
MATCH (a)-[r:DIRECTED]->()
RETURN a.name, r
(no changes, no records)
This is because the second MATCH
clause returns no data (there are no DIRECTED
relationships connected to Martin Sheen
in the graph) to pass on to the RETURN
clause.
However, replacing the second MATCH
clause with OPTIONAL MATCH
does return results. This is because, unlike MATCH
, OPTIONAL MATCH
enables the value null
to be passed between clauses.
这是因为第二个MATCH
子句没有返回任何数据(图中没有DIRECTED
连接到的关系Martin Sheen
)以传递到该RETURN
子句。
但是,将第二个MATCH
子句替换为OPTIONAL MATCH
确实会返回结果。这是因为,与 不同MATCH
,OPTIONAL MATCH
它允许值null
在子句之间传递。
MATCH (p:Person {name: 'Martin Sheen'})
OPTIONAL MATCH (p)-[r:DIRECTED]->()
RETURN p.name, r
p.name | r |
---|---|
|
|
Rows: 1 |
OPTIONAL MATCH
can therefore be used to check graphs for missing as well as existing values, and to pass on rows without any data to subsequent clauses in a query.
Optional relationships
If the existence of a relationship is optional, use the OPTIONAL MATCH
clause. If the relationship exists, it is returned. If it does not, null
is returned in its place.
MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-->(x)
RETURN x
Returns null
, since the Movie
node Wall Street
has no outgoing relationships.
x |
---|
|
Rows: 1 |
On the other hand, the following query does not return null
since the Person
node Charlie Sheen
has one outgoing relationship.
MATCH (a:Person {name: 'Charlie Sheen'})
OPTIONAL MATCH (a)-->(x)
RETURN x 见上面的图即可知道答案是wall street
x |
---|
|
Rows: 2 |
Properties on optional elements
If the existence of a property is optional, use the OPTIONAL MATCH
clause. null
will be returned if the specified property does not exist.
MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name
Returns the element x
(null
in this query), and null
for its name
property, because the Movie
node Wall Street
has no outgoing relationships.
x | x.name |
---|---|
|
|
Rows: 1 |
The following query only returns null
for the nodes which lack a name
property.
MATCH (a:Person {name: 'Martin Sheen'})
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name 见上图即知为啥有三个答案
x | x.name |
---|---|
|
|
|
|
|
|
Rows: 3 |
Optional typed and named relationship
It is also possible to look for specific relationship types when using OPTIONAL MATCH
:
MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-[r:ACTED_IN]->()
RETURN a.title, r
This returns the title of the Movie
node Wall Street
, and since this node has no outgoing ACTED_IN
relationships, null
is returned for the relationship denoted by the variable r
.
a.title | r |
---|---|
|
|
Rows: 1 |
However, the following query does not return null
since it is looking for incoming relationships of the type ACTED_IN
to the Movie
node Wall Street
.
MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (x)-[r:ACTED_IN]->(a)
RETURN a.title, x.name, type(r)
a.title | x.name | type(r) |
---|---|---|
|
|
|
|
|
|
|
|
|
Rows: 3 |