我的图形模型应允许从父级继承到子级的属性,并在子级上覆盖此类继承的属性。属性是以HAS
关系附加的节点。
CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute:Name {value: "Indirect Name"})
CREATE (parent)-[:HAS]->(:Attribute:Other {value: "Other Attribute"})
CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute:Name {value: "Direct Name"})
CREATE (c1)-[:BELONGS_TO]->(parent)
CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)
在此示例中,我们有C1-[:BELONGS_TO]->P
和C2-[:BELONGS_TO]->P
。 P
定义了继承的属性Name
和未继承的属性Other
。 C1
覆盖了Name
属性,而C2
继承了该属性。
我现在要查找属于某个节点的所有相关属性:C1的直接附加名称属性和C2的间接名称属性。对于C1和C2,不应考虑“其他”属性,因为它不是继承的。
要获取所有直接和继承的属性,我可以使用此查询:
MATCH (c {id: "C1"})-[:HAS]->(directAttribute:Attribute), (c)-[]->(:Node)-[:HAS{inherited: true}]->(inheritedAttribute:Attribute) RETURN directAttribute, inheritedAttribute
但是显然,这将同时返回Name
属性,C1
属性和P
继承属性。我们该如何“偏爱”直接附加到继承节点上而不是继承节点上的属性,以便在这种情况下,查询只能返回“直接”名称属性?
使用节点标签在属性名称之间进行区分对于您的用例而言非常笨拙。我建议将属性名称改为属性名称。例如,在以下数据创建查询中为name
和other
(以及foo
,以显示如何具有多个继承的属性):
CREATE (parent:Node {id: "P"})-[:HAS {inherited: true}]->(:Attribute {name: "Indirect Name", foo: "Bar"})
CREATE (parent)-[:HAS]->(:Attribute {other: "Other Attribute"})
CREATE (c1:Node {id: "C1"})-[:HAS]->(:Attribute {name: "Direct Name"})
CREATE (c1)-[:BELONGS_TO]->(parent)
CREATE (c2:Node {id: "C2"})-[:BELONGS_TO]->(parent)
然后,您可以使用方便的APOC功能apoc.map.merge获取“ C1”的适用属性。
例如,此查询:
MATCH (c:Node {id: "C1"})
OPTIONAL MATCH (c)-[:HAS]->(da:Attribute)
OPTIONAL MATCH (c)-[:BELONGS_TO]->()-[:HAS {inherited: true}]->(ia:Attribute)
RETURN c, apoc.map.merge(ia, da) AS attrs
获得此结果:
╒═══════════╤══════════════════════════════════╕
│"c" │"attrs" │
╞═══════════╪══════════════════════════════════╡
│{"id":"C1"}│{"name":"Direct Name","foo":"Bar"}│
└───────────┴──────────────────────────────────┘
对“ C2”的相同查询将得到以下结果:
╒═══════════╤════════════════════════════════════╕
│"c" │"attrs" │
╞═══════════╪════════════════════════════════════╡
│{"id":"C2"}│{"name":"Indirect Name","foo":"Bar"}│
└───────────┴────────────────────────────────────┘
您可能还想使用其他关系类型(例如[:INHERITS]
)代替[:HAS {inherited: true}]
。