我有这样一个图表
每个节点都有唯一的nodeId
属性,该属性由Neo4j约束保证。每个关系都有唯一的id
属性。Ne4j的版本为4.3.7。
浅绿色节点是公司,粉色节点是人,其他节点是不能存储在节点内的附加信息。在这里,“彼得公司”有两个费用,主要地址,次要地址,成立日期和终止日期。
我想删除“彼得公司”及其董事的旧信息。为此,我使用了这样一个查询:
UNWIND $batch AS data
MATCH (n:Entity { nodeId: data.entityId })
OPTIONAL MATCH (n)-[rel]->(prop:Property)
WHERE NOT prop.nodeId IN data.propertyIds
DELETE rel
WITH prop
WHERE NOT exists(()-->(prop))
DELETE prop
其中,本例中的$batch
是
[
{
'entityId': '0000',
'propertyIds': ['0002', '0003', '0004', '0005', '0006', '0009']
},
{
'entityId': '0001',
'propertyIds': ['0004', '0010']
},
]
entityId
是节点的nodeId
,propertyIds
是当前附加信息(属性)的nodeId
。如果存在从实体到ID不在propertyIds
中的属性的连接,则这是旧信息,必须删除它们之间的边。此外,如果特性在此之后没有更多的传入边(它只能具有传入边),则会将其删除。
上面的列表包含公司及其董事的ID及其当前财产的ID。与“其他公司”有关联的日期对“Peter Company”已过时,其nodeId
不在上面的批次中。作为查询的结果,我预计必须删除从公司到旧物业的连接,而不删除该物业。
但我得到了一个错误:
Cannot delete node<18>, because it still has relationships. To delete this node, you must first delete its relationships.
为什么我收到一个错误?节点18有一个来自“Other Company”的传入连接,因此exists(()-->(prop))
必须返回true
。
如果将该表达式更改为exists(()--(prop))
,则不会出现错误。
如果我在查询中将DELETE
替换为SET
:
UNWIND $batch AS data
MATCH (n:Entity { nodeId: data.entityId })
OPTIONAL MATCH (n)-[rel]->(prop:Property)
WHERE NOT prop.nodeId IN data.propertyIds
SET rel.toPrune = true
WITH prop
WHERE NOT exists(()-->(prop))
SET prop.toPrune = true
则标记关系而不标记节点,即,exists(()-->(prop))
返回true
。
我用Python语言创建了一个重现该问题的示例:
from neo4j import GraphDatabase
with GraphDatabase.driver("bolt://localhost:7687", auth=('neo4j', 'neo')) as driver, \
driver.session() as session:
create_graph = """
MERGE (n1:Test:Entity:Company {nodeId: "0000"}) SET n1.name = "Peter company"
MERGE (n2:Test:Entity:Person {nodeId: "0001"}) SET n2.name = "Peter"
MERGE (n3:Test:Property:Charge {nodeId: "0002"}) SET n3.status = "closed"
MERGE (n4:Test:Property:Charge {nodeId: "0003"}) SET n4.status = "opened"
MERGE (n5:Test:Property:Address {nodeId: "0004"}) SET n5.country = "France"
MERGE (n6:Test:Property:Address {nodeId: "0005"})
SET n6.country = "France"
SET n6.city = "Ham Les Varennes"
MERGE (n7:Test:Property:Date {nodeId: "0006"})
SET n7.date = datetime("2014-09-04T00:00:00")
SET n7.monthIsKnown = true
SET n7.dayIsKnown = true
MERGE (n8:Test:Property:Date {nodeId: "0007"})
SET n8.date = datetime("1962-01-01T00:00:00")
SET n8.monthIsKnown = false
SET n8.dayIsKnown = false
MERGE (n9:Test:Entity:Company {nodeId: "0008"}) SET n9.name = "Other company"
MERGE (n10:Test:Property:Date {nodeId: "0009"})
SET n10.date = datetime("1962-01-01T00:00:00")
SET n10.monthIsKnown = false
SET n10.dayIsKnown = false
MERGE (n11:Test:Property:Date {nodeId: "0010"})
SET n11.date = datetime("1976-01-01T00:00:00")
SET n11.monthIsKnown = false
SET n11.dayIsKnown = false
MERGE (n1)-[:HAS_CHARGE {id: 1}]->(n3)
MERGE (n1)-[:HAS_CHARGE {id: 2}]->(n4)
MERGE (n1)-[:HAS_PRIMARY_ADDRESS {id: 3}]->(n5)
MERGE (n1)-[:HAS_SECONDARY_ADDRESS {id: 4}]->(n6)
MERGE (n1)-[:HAS_TERMINATION_DATE {id: 5}]->(n7)
MERGE (n1)-[:HAS_CREATION_DATE {id: 6}]->(n8)
MERGE (n1)-[:HAS_CREATION_DATE {id: 7}]->(n10)
MERGE (n2)-[:FR_DIRECTOR {id: 8}]->(n1)
MERGE (n2)-[:HAS_COUNTRY_OF_RESIDENCE {id: 9}]->(n5)
MERGE (n2)-[:HAS_DATE_OF_BIRTH {id: 10}]->(n11)
MERGE (n9)-[:HAS_CREATION_DATE {id: 11}]->(n8)
"""
with session.begin_transaction() as tx:
tx.run(create_graph)
batch = [
{
'entityId': '0000',
'propertyIds': ['0002', '0003', '0004', '0005', '0006', '0009']
},
{
'entityId': '0001',
'propertyIds': ['0004', '0010']
},
]
clean_old_properties = """
UNWIND $batch AS data
MATCH (n:Entity { nodeId: data.entityId })
OPTIONAL MATCH (n)-[rel]->(prop:Property)
WHERE NOT prop.nodeId IN data.propertyIds
DELETE rel
WITH prop
WHERE NOT exists(()-->(prop))
DELETE prop
"""
with session.begin_transaction() as tx:
tx.run(clean_old_properties, dict(batch=batch))
一个有趣的注意事项:如果本例中的两个查询都在一个事务中执行,则不会发出错误。
1条答案
按热度按时间xzv2uavs1#
该错误是由Neo4j内核中的错误引起的。该问题已在版本4.4.12中修复。
内核
更改日志
Related issue