当唯一性基于节点属性和关系存在时在Neo4j中合并

时间:2019-06-19 11:59:46

标签: neo4j

在我的模型中,我有两种类型的节点:系统和数据集。每个数据集都属于一个系统。这由CONTAINS_DATASET关系表示。

enter image description here

作为一般规则;数据集名称在给定系统中必须唯一。如果数据集包含在不同的系统中,则允许重复的数据集名称。

enter image description here

我正在尝试通过Cypher强制执行;当有人尝试创建一个包含在系统中的数据集时;如果数据集的名称与该系统的CONTAINED_IN中的现有数据集不匹配,则Cypher只会创建一个新的数据集。

我想我需要一个MERGE语句,其中包含基于与系统的关系的过滤条件,但是我不知道该怎么做。我已经在下面包含了我正在使用的代码,但是它只是一个合并,不考虑数据集所驻留的系统。

:params
  "data": {
    "System": [
      {
        "name": "System 1",
        "datasets": [
          {
            "name": "Customers"
          }
        ]
      },
      {
        "name": "System 2",
        "datasets": [
          {
            "name": "Customers"
          }
        ]
      },
      {
        "name": "System 3",
        "datasets": [
          {
            "name": "Products"
          }
        ]
      }
    ]
  }

UNWIND {data} as data
UNWIND data.System as systems
UNWIND systems.datasets as datasets
MERGE (sy:System { name: systems.name})
    ON CREATE SET sy.status='New'
    ON MATCH SET  sy.status='Updated'
MERGE (da:Dataset { name: datasets.name})
MERGE (sy)-[:CONTAINS_DATASET]->(dan:Dataset { name: datasets.name })
return *

上面的查询还创建了两个我没想到的其他节点,因此对此的任何帮助也将不胜感激:

enter image description here

1 个答案:

答案 0 :(得分:2)

您在这里很近,您的Cypher实际上拥有您需要的解决方案:

MERGE (sy)-[:CONTAINS_DATASET]->(dan:Dataset { name: datasets.name })

此模式具有一个绑定变量(先前与图形元素匹配)sy,以及一个未绑定变量(先前不与任何元素匹配,在查询中首次出现)变量dan

MERGE就像对模式进行匹配,然后行为将根据该模式是否存在于图形中而改变。

如果它存在于图中(sy与具有给定名称的:Dataset节点具有:CONTAINS_DATASET关系),则它将重用现有的图结构,并且dan将绑定到该图结构现有的连接节点。

如果图形中不存在该模式,则将创建整个模式,这将包括创建任何未绑定的节点,例如dan。如果该模式不存在,它将锁定该模式(sy)的绑定部分,进行仔细检查以确保在检查时间和锁定时间之间没有任何更改,然后它将创建模式中先前未绑定的部分。 sy是先前绑定的,因此它将使用同一节点而不是创建一个新节点。 (dan:Dataset { name: datasets.name })之前未绑定,因此将创建具有此标签和此属性的新节点,并通过:CONTAINS_DATASET关系将其连接到sy

因此,此行为应完全满足您的需要,重复使用具有该名称的已连接节点(如果存在),或创建一个具有该名称的全新节点并按sy节点进行连接。

对于您看到的重复项,这是因为该行之前的行:

MERGE (da:Dataset { name: datasets.name})

这不是必需的,您已经可以在其后的一行中满足您的需求,因此请将其删除,您的查询应该会为您服务。

有关our knowledge base article中MERGE行为的更多详细信息。