触发器
触发器允许注册 Cypher 查询,这些查询会在 Neo4j 中的数据发生更改(创建、更新、删除)时被调用。触发器可以在事务提交之前或之后运行。
有以下几种方法可以实现
此外, |
安装、更新或删除触发器是一个最终一致性操作。因此,它们不会立即添加/更新/删除,而是有一个由 APOC 配置 |
默认情况下触发器是禁用的。我们可以通过在 apoc.conf
中设置以下属性来启用它们
apoc.trigger.enabled=true
apoc.trigger.refresh=60000
选项键 | 值 | 描述 |
---|---|---|
apoc.trigger.enabled |
true/false,默认 false |
启用/禁用此功能 |
apoc.trigger.refresh |
数字,默认 60000 |
在所有集群节点之间触发复制检查的时间间隔(毫秒) |
合格名称 | 类型 |
---|---|
apoc.trigger.drop |
|
apoc.trigger.dropAll |
|
apoc.trigger.install |
|
apoc.trigger.list |
|
apoc.trigger.show |
|
apoc.trigger.start |
|
apoc.trigger.stop |
|
Neo4j 的事务数据被转换为适当的数据结构,以作为语句的参数被消费,即 $createdNodes
。
可用参数有
语句 | 描述 |
---|---|
|
返回事务的 ID。 请注意,此值仅适用于“after”和“afterAsync”阶段(请参阅触发器阶段表)。否则,其值为 |
|
返回事务的日期(毫秒) |
|
当节点创建时触发(节点列表) |
|
当关系创建时触发(关系列表) |
|
当节点删除时触发(节点列表) |
|
当关系删除时触发(关系列表) |
|
当标签移除时触发(标签到节点列表的映射) |
|
当节点属性移除时触发(键到键、旧值、节点映射列表的映射) |
|
当关系属性移除时触发(键到键、旧值、关系映射列表的映射) |
|
当标签分配时触发(标签到节点列表的映射) |
|
当节点属性分配时触发(键到键、旧值、新值、节点映射列表的映射) |
|
当关系属性分配时触发(键到键、旧值、新值、关系映射列表的映射) |
|
一个包含该事务元数据的映射。事务元数据可以在客户端设置,例如通过 https://neo4j.ac.cn/docs/api/java-driver/current/org.neo4j.driver/org/neo4j/driver/TransactionConfig.html#metadata() |
apoc.trigger.install()
的第三个参数是一个映射 {phase: PHASE}
,其中 PHASE
是一个字符串,可以具有以下值之一
|
描述 |
|
触发器将在提交 |
|
触发器将在 |
|
触发器将在提交 |
|
触发器将在提交 |
与以前的 Neo4j 版本不同,在 Neo4j 5 中将无法修改在“after”阶段创建的实体。例如,以下查询将返回带有消息
因此,需要使用另一个阶段或仅执行读取操作。 |
触发器示例
可以添加一个触发器,当在节点上添加特定属性时,它会将相同的属性添加到连接到该节点的所有节点。
数据集(在默认数据库 'neo4j' 中)
CREATE (d:Person {name:'Daniel', surname: 'Craig'})
CREATE (l:Person {name:'Mary', age: 47})
CREATE (t:Person {name:'Tom'})
CREATE (j:Person {name:'John'})
CREATE (m:Person {name:'Michael'})
CREATE (a:Person {name:'Anne'})
CREATE (l)-[:DAUGHTER_OF]->(d)
CREATE (t)-[:SON_OF]->(d)
CREATE (t)-[:BROTHER]->(j)
CREATE (a)-[:WIFE_OF]->(d)
CREATE (d)-[:SON_OF]->(m)
CREATE (j)-[:SON_OF]->(d)

使用上述数据集,如果添加了触发器并执行以下查询:MATCH (n:Person) WHERE n.name IN ['Daniel', 'Mary'] SET n.age=55, n.surname='Quinn'
,则触发器语句中使用的 $assignedNodeProperties
将如下所示(其中 NODE(1)
是 (:Person {name: 'Daniel'})
,NODE(2)
是 (:Person {name: 'Mary'})
)
{
age: [{
node : NODE(1),
new: 55,
old: null,
key: "age"
},
{
node: NODE(2),
new: 55,
old: 47,
key: "age"
}],
surname: [{
node: NODE(1),
new: "Quinn",
old: "Craig",
key: "surname"
},
{
node: NODE(2),
new: "Quinn",
old: null,
key: "surname"
}]
}
结果是一个映射,其中键是分配的属性,值是涉及的实体列表。列表的每个元素都包含节点本身、更改属性的新值、旧值(如果属性不存在则为 null
)以及带有属性名称的键。
$removedNodeProperties
参数具有相同的结构和逻辑(在这种情况下,new
值将始终为 null
)。
assignedRelationshipProperties
和 removedRelationshipProperties
也是如此,唯一的区别是 node: NODE(n)
键被 relationship: RELATIONSHIP(n)
键替换。
例如,以下语句创建一个触发器,对于每个 SET
,它会用当前日期更新 time
和 lasts
这两个属性
CALL apoc.trigger.install('neo4j', 'setLastUpdate',
"
UNWIND keys($assignedNodeProperties) AS k
UNWIND $assignedNodeProperties[k] AS map
WITH map.node AS node, collect(map.key) AS propList
MATCH (n)
WHERE id(n) = id(node) AND NOT 'lasts' in propList // to prevent loops
SET n.time = date(), n.lasts = propList
",
{phase: 'afterAsync'});
请注意,apoc.trigger.install
以及 apoc.trigger.drop
、apoc.trigger.dropAll
、apoc.trigger.stop
和 apoc.trigger.start
必须在系统数据库中执行。
在上面的示例中,MATCH (n) WHERE id(n) = id(node)
用于演示首先通过 id 查找节点,然后再设置其参数。但是,更高效的方法是移除此命令,并将倒数第二行更改为:SET node.time = date(), node.lasts = propList
。请注意,必须添加条件 AND NOT 'lasts' IN propList
以防止无限循环,因为 SET
命令将再次触发此查询。
然后可以在由配置 apoc.trigger.refresh
定义的时间之后执行以下查询
MATCH (n:Person {name: 'Daniel'}) set n.age = 123, n.country = 'Italy'
执行中
MATCH (n:Person {name: 'Daniel'}) return n
可以将属性 time
设置为今天的日期,并将 lasts=['country','age']
。
在将 surname
属性添加到节点的情况下,它也会被添加到连接到该节点的所有节点(在本例中深度为一层)。
MATCH (d:Person {name:'Daniel'})
SET d.surname = 'William'
要添加一个触发器,用于连接每个带有标签 Actor
的新节点并为 name
属性分配特定值,请运行以下查询
CALL apoc.trigger.install('neo4j','create-rel-new-node',
"
UNWIND $createdNodes AS n
MATCH (m:Movie {title:'Matrix'})
WHERE n:Actor AND n.name IN ['Keanu Reeves','Laurence Fishburne','Carrie-Anne Moss']
CREATE (n)-[:ACT_IN]->(m)
",
{phase:'before'}
)
CREATE (k:Actor {name:'Keanu Reeves'})
CREATE (l:Actor {name:'Laurence Fishburne'})
CREATE (c:Actor {name:'Carrie-Anne Moss'})
CREATE (a:Actor {name:'Tom Hanks'})
CREATE (m:Movie {title:'Matrix'})

在包含 $deletedRelationships
或 $deletedNodes
的触发器查询中,无法使用 Cypher 函数 properties()
检索已删除实体的属性,因为已删除实体表示为虚拟节点和虚拟关系。相反,触发器查询必须使用 apoc.any.properties
函数来检索已删除节点和关系的属性
CALL apoc.trigger.install('neo4j', 'createLogNodeOnDelete',
"
UNWIND $deletedNodes as deletedNode
CREATE (log:Log) (1)
SET log:$(labels(deletedNode)) (2)
SET log += apoc.any.properties(deletedNode) (3)
",
{phase: 'afterAsync'});
1 | 为每个已删除节点创建一个带有标签 Log 的节点。 |
2 | 使用 动态标签 将已删除节点的标签添加到 Log 节点。请注意,labels 被分配给已删除的节点。 |
3 | 使用 apoc.any.properties 函数将已删除节点的属性添加到 Log 节点。 |
给定此触发器,已删除节点的标签和属性将按如下方式分配给 Log
节点
Person
节点CREATE (d:Person:Actor {name:'Daniel', surname: 'Craig'})
Person
节点MATCH (n:Person {name: "Daniel"})
DETACH DELETE n
Log
节点返回有关已删除节点的信息MATCH (n:Log) RETURN n
n |
---|
(:Log:Person:Actor {surname: "Craig",name: "Daniel"}) |
为了防止某些事务锁,通常建议使用 afterAsync
阶段。这将阻止查询无限期地挂起。
请注意,apoc.trigger.stop
和 apoc.trigger.start
过程是最终一致的。因此,需要等待一定时间才能使更改传播。等待时间由配置 apoc.trigger.refresh
定义。
要暂停触发器而不删除它以备将来使用,请使用以下过程

要恢复已暂停的触发器,请使用以下过程

添加 \{params: {parameterMaps}}
以插入附加参数。
CALL apoc.trigger.install('neo4j', 'timeParams',
"UNWIND $createdNodes AS n SET n.time = $time",
{}, {params: {time: timestamp()}}
);
CALL apoc.trigger.install('neo4j', 'timestamp',
"UNWIND $createdNodes AS n SET n.ts = timestamp()",
{});
CALL apoc.trigger.install('neo4j', 'lowercase',
"UNWIND $createdNodes AS n SET n.id = toLower(n.name)",
{});
CALL apoc.trigger.install('neo4j', 'txInfo',
"UNWIND $createdNodes AS n SET n.txId = $transactionId, n.txTime = $commitTime",
{phase:'after'});
CALL apoc.trigger.install('neo4j', 'count-removed-rels',
"MATCH (c:Counter) SET c.count = c.count + size([r IN $deletedRelationships WHERE type(r) = "X"])",
{})
移除触发器
要在 'neo4j' 数据库中移除名为 'test' 的触发器,请运行以下查询
CALL apoc.trigger.drop('neo4j', 'test')
要在 'neo4j' 数据库中移除所有触发器,请运行以下查询
CALL apoc.trigger.dropAll('neo4j')
触发器列表
可以返回数据库中触发器的完整列表。例如,如果创建了以下查询中的触发器
CALL apoc.trigger.install('neo4j', 'count-removals',
"MATCH (c:Counter) SET c.count = c.count + size([f IN $deletedNodes WHERE id(f) > 0])",
{})
然后可以运行(同样在此情况下,在由配置 apoc.trigger.refresh
定义的时间之后)
CALL apoc.trigger.show('neo4j')
名称 | 查询 | 选择器 | 参数 | 已安装 | 已暂停 |
---|---|---|---|---|---|
"count-removals" |
{} |
{} |
TRUE |
FALSE |
请注意,由于触发器操作是最终一致的(基于 |