模式

Cypher® 依赖 模式匹配 来查找数据。模式通常用于 MATCH 语句中,例如

MATCH (m:Movie)<-[:ACTED_IN]-(a:Actor)

模式可以极其复杂,而 @neo4j/cypher-builder 提供了定义这些模式所需的工具。

节点和关系

模式由节点和关系组成。第一步是定义模式中引用的变量。

const person = new Cypher.Node();
const movie = new Cypher.Node();
const actedIn = new Cypher.Relationship();

基础模式

所有模式都以节点开头和结尾。通过使用之前定义的变量,模式可以定义如下

const pattern = new Cypher.Pattern(person, { labels: ["Person"] }).related(actedIn, { type: "ACTED_IN" }).to(movie, { labels: ["Movie"] });

此模式现在可以在任何可以使用模式的地方使用,例如在 MATCH 子句中。

new Cypher.Match(pattern);
MATCH (this0:Person)-[this1:ACTED_IN]->(this2:Movie)

关系方向

默认情况下,模式中的关系被创建为从左到右的模式。在使用 direction 属性在模式中定义关系时,可以更改方向。

const pattern = new Cypher.Pattern(person)
    .related(actedIn, { type: "ACTED_IN", direction: "left" })
    .to(movie);

这会转换为以下模式

(this0)<-[this1:ACTED_IN]-(this2)

direction 的选项包括

  • right(默认):从左到右 (()-[]→()) 的模式。

  • left:从右到左 (()←[]-()) 的模式。

  • undirected:无向 (()-[]-()) 模式。

移除变量名

模式中的节点和关系变量是可选的,如果不传递变量,它将不会在 Cypher 中呈现。

const pattern = new Cypher.Pattern(person, { labels: ["Person"] }).related({type: "ACTED_IN"}).to({labels: ["Movie"]});

这会转换为

(this0:Person)-[:ACTED_IN]->(:Movie)

移除标签和类型

标签和类型在模式中是可选的。

const pattern = new Cypher.Pattern(person).related(actedIn).to(movie, { labels: ["Movie"] });
(this0)-[this1]->(this1:Movie)

标签和类型也可以在 Cypher.NodeCypher.Relationship 中定义,此行为已被弃用,未来将被移除。

属性

模式可能包含用于匹配节点和关系的属性。这些可以使用 properties 参数添加。

const pattern = new Cypher.Pattern(person, {
    labels: ["Person"],
    properties: { name: new Cypher.Param("Person") },
}).related(actedIn, { type: "ACTED_IN" })
  .to(movie, { labels: ["Movie"] });
(this0:Person { name: $param0 })-[this1:ACTED_IN]->(this2:Movie)

properties 参数接受一个对象,其中包含要匹配的属性以及用作模式期望值的参数对象。它可用于节点和关系元素。

高级模式

本节展示如何定义更复杂的模式。

更长的模式

模式可以是任意长度。例如

const user = new Cypher.Node();

const pattern = new Cypher.Pattern({labels: ["Person"]}).related({type: "ACTED_IN"}).to().related({direction: "left"}).to(user, { labels: ["User"] });
(:Person)-[:ACTED_IN]->()<-[]-(this1:User)

循环

模式可能包含循环。为此,您可以重复使用相同的变量。

const actor = new Cypher.Node();
const movie = new Cypher.Node();

const actedIn = new Cypher.Relationship();
const directed = new Cypher.Relationship();

const pattern = new Cypher.Pattern(person, { labels: ["Person"] })
    .related(actedIn, { type: "ACTED_IN" })
    .to(movie, { labels: ["Movie"] })
    .related(directed, { direction: "undirected", type: "DIRECTED" })
    .to(actor);

这会转换为

(this0:Person)-[this1:ACTED_IN]->(this2:Movie)-[this3:DIRECTED]-(this0)

请注意模式中的初始节点 (this0) 与最后一个元素中引用的节点相同。这可以匹配既是演员又导演了同一部电影的人。

长度

关系的长度(或跳数)可以使用 length 属性定义。

精确长度

可以通过传递一个数字来定义精确长度。

const pattern = new Cypher.Pattern({}).related(actedIn, { type: "ACTED_IN", length: 3 }).to();
MATCH ()-[this1:ACTED_IN*3]->()

最小和最大长度

可以通过传递一个包含以下选项的对象来选择性地添加边界

  • min:定义关系的最小长度。

  • max:定义关系的最大长度。

例如:

const pattern = new Cypher.Pattern({}).related(actedIn, { type: "ACTED_IN", length: {min: 2, max: 10} }).to();
MATCH ()-[this1:ACTED_IN*2..10]->()

任意长度

通过使用字符串 "*",将匹配任意长度的关系。

const pattern = new Cypher.Pattern({}).related(actedIn, { type: "ACTED_IN", length: "*" }).to();
MATCH ()-[this1:ACTED_IN*]->()

WHERE 谓词

WHERE 子句可用作模式中节点和关系的谓词。

const movie = new Cypher.Node({ labels: ["Movie"] });

new Cypher.Pattern(movie, { labels: ["Movie"] }).where(Cypher.eq(movie.property("title"), new Cypher.Literal("The Matrix")));
(this0:Movie WHERE this0.title = "The Matrix")

标签表达式

通过使用 标签表达式,可以将复杂的标签过滤器作为模式的一部分添加。以下是可用的表达式

  • labelExpr.and

  • labelExpr.or

  • labelExpr.not

  • labelExpr.wildcard

例如:

const movieNode = new Cypher.Node();

const matchQuery = new Cypher.Match(
    new Cypher.Pattern(movieNode, {
        labels: Cypher.labelExpr.and(Cypher.labelExpr.or("Movie", "Film"), Cypher.labelExpr.not("Show")),
    })
).return(movieNode);
MATCH (this0:((Movie|Film)&!Show))
RETURN this0

默认情况下,模式中的多个标签使用 : 组合(例如 (m:Film:Movie)),这与标签表达式不兼容。如果您正在使用标签表达式并在同一查询中向模式传递多个标签,请确保在 .build 中将 labelOperator 选项设置为 "&"

matchQuery.build({
    labelOperator: "&"
})

动态标签和类型

模式中的标签和关系类型可以是动态表达式。要使标签动态化,只需将任何 Cypher 表达式传递给 labelstype 即可。这会将表达式包装在 $() 中。

示例 1:使用参数作为节点标签

const query = new Cypher.Match(
    new Cypher.Pattern(new Cypher.Node(), {
        labels: new Cypher.Param("Movie"),
    })
)
MATCH (this0:$($param0))

示例 2:关系上的动态类型

关系类型同理

const query = new Cypher.Match(
    new Cypher.Pattern()
        .related({
            type: new Cypher.Param("ACTED_IN"),
        })
        .to()
)
MATCH ()-[:$($param1)]->()

示例 3:将标签表达式与动态标签一起使用

const movieLabel = new Cypher.Variable();

const query = new Cypher.With([new Cypher.Literal("Movie"), movieLabel])
    .match(
        new Cypher.Pattern(new Cypher.Node(), {
            labels: Cypher.labelExpr.or(
                movieLabel,
                Cypher.labelExpr.not(new Cypher.Param("paramLabel"))
            ),
        })
    )
WITH "Movie" AS var0
MATCH (this1:($(var0)|!$($param1)))

量化路径模式

量化路径模式 可以使用 Cypher.QuantifiedPath 类来定义。

QuantifiedPath 代表量化模式或普通模式的并集。例如

const m = new Cypher.Node();
const m2 = new Cypher.Node();

const quantifiedPath = new Cypher.QuantifiedPath(
    new Cypher.Pattern(m, { labels: ["Movie"], properties: { title: new Cypher.Param("V for Vendetta") } }),
    new Cypher.Pattern({ labels: ["Movie"] })
        .related({ type: "ACTED_IN" })
        .to({ labels: ["Person"] })
        .quantifier({ min: 1, max: 2 }),
    new Cypher.Pattern(m2, {
        labels: ["Movie"],
        properties: { title: new Cypher.Param("Something's Gotta Give") },
    })
);

const query = new Cypher.Match(quantifiedPath).return(m2);

生成以下 Cypher

MATCH (this0:Movie { title: $param0 })
      ((:Movie)-[:ACTED_IN]->(:Person)){1,2}
      (this1:Movie { title: $param1 })
RETURN this1

请注意,QuantifiedPath 要求至少一个模式具有量词。这可以通过普通 Pattern 类的 .quantifier 方法来完成。此方法将 (:Movie)-[:ACTED_IN]→(:Person) 这样的模式转换为量化模式:(:Movie)-[:ACTED_IN]→(:Person){1,2}

quantifier 方法接受一个参数,可以是以下之一

  • 一个数字,定义精确长度。

  • 一个包含可选属性 min, max 的对象。

  • 字符串 +*

转义标签和类型

如果检测到任何不常见的字符,标签和类型将自动转义。例如

const movie = new Cypher.Node();
const match = new Cypher.Match(movie, { labels: ["My Movie"] }).return(movie);
MATCH (this0:`My Movie`)
RETURN this0

请注意,My Movie 被引号括起来,以防止通过动态标签进行代码注入。

部分模式

所有模式都以节点开头和结尾。但是,通过在没有 .to 的情况下使用 .related,可以定义一个部分模式

const partialPattern = new Cypher.Pattern(person).related(actedIn);

在这种情况下,在通过 .to 方法完成之前,部分模式不能用于任何子句中。

partialPattern.to(movie)
© . This site is unofficial and not affiliated with Neo4j, Inc.