从JSON创建节点和关系(动态)

从JSON创建节点和关系(动态),json,neo4j,cypher,Json,Neo4j,Cypher,我在一个类似以下示例的结构中有几百个JSON: { "JsonExport": [ { "entities": [ { "identity": "ENTITY_001", "surname": "SMIT", "entityL

我在一个类似以下示例的结构中有几百个JSON:

{
"JsonExport": [
    {
        "entities": [
            {
                "identity": "ENTITY_001",
                "surname": "SMIT",
                "entityLocationRelation": [
                    {
                        "parentIdentification": "PARENT_ENTITY_001",
                        "typeRelation": "SEEN_AT",
                        "locationIdentity": "LOCATION_001"
                    },
                    {
                        "parentIdentification": "PARENT_ENTITY_001",
                        "typeRelation": "SEEN_AT",
                        "locationIdentity": "LOCATION_002"
                    }
                ],
                "entityEntityRelation": [
                    {
                        "parentIdentification": "PARENT_ENTITY_001",
                        "typeRelation": "FRIENDS_WITH",
                        "childIdentification": "ENTITY_002"
                    }
                ]
            },
            {
                "identity": "ENTITY_002",
                "surname": "JACKSON",
                "entityLocationRelation": [
                    {
                        "parentIdentification": "PARENT_ENTITY_002",
                        "typeRelation": "SEEN_AT",
                        "locationIdentity": "LOCATION_001"
                    }
                ]
            },
            {
                "identity": "ENTITY_003",
                "surname": "JOHNSON"
            }
        ],
        "identification": "REGISTRATION_001",
        "locations": [
            {
                "city": "LONDON",
                "identity": "LOCATION_001"
            },
            {
                "city": "PARIS",
                "identity": "LOCATION_002"
            }
        ]
    }
]
}
有了这些JSON,我想制作一个由以下节点组成的图:注册、实体和位置。这一部分我已经弄明白了,并做了如下工作:

WITH "file:///example.json" AS json_file
CALL apoc.load.json(json_file,"$.JsonExport.*" ) YIELD value AS data
MERGE(r:Registration {id:data.identification})
WITH json_file
CALL apoc.load.json(json_file,"$.JsonExport..locations.*" ) YIELD value AS locations
MERGE(l:Locations{identity:locations.identity, name:locations.city})
WITH json_file
CALL apoc.load.json(json_file,"$.JsonExport..entities.*" ) YIELD value AS entities
MERGE(e:Entities {name:entities.surname, identity:entities.identity})
所有实体和地点都应与注册有关。我想我可以通过使用以下代码来做到这一点:

MERGE (e)-[:REGISTERED_ON]->(r)
MERGE (l)-[:REGISTERED_ON]->(r)
但是,此代码没有提供所需的输出。它会创建额外的“空”节点,并且不会连接到注册节点。因此,第一个问题是:如何将位置和实体节点连接到注册节点。根据其他JSON,实体和位置应该只链接到特定的注册

此外,我希望创建实体->位置关系和实体-实体关系,并使用给定类型的关系(SEEN_AT或FRIENDS_WITH)作为给定关系的标签。如何做到这一点?我在这一点上有点迷茫,不知道如何解决这个问题。如果有人能把我引向正确的方向,我将不胜感激

  • 变量名(如
    e
    r
    )不存储在数据库中,仅绑定到单个查询中的值<对具有未绑定变量的模式进行代码>合并只会创建整个模式(包括为未绑定节点变量创建空节点)

  • 创建节点时,应仅指定该节点的唯一标识属性,以避免重复。创建时要设置的任何其他属性都应使用“创建集”上的
    进行设置

  • 对JSON数据进行三次解析以获得数据的不同区域是低效的。而且查询的方式效率尤其低下,因为每个后续的
    调用/合并
    子句组都会执行多次(因为每个先前的
    调用
    都会生成多行,并且行数会成倍增加)。您可以使用来绕过这一点,但在您的情况下,这是不必要的,因为您可以在一次通过JSON数据的过程中完成整个查询

  • 这可能适用于您:

    CALL apoc.load.json(json_file,"$.JsonExport.*" ) YIELD value AS data
    MERGE(r:Registration {id:data.identification})
    FOREACH(ent IN data.entities |
      MERGE (e:Entities {identity: ent.identity})
      ON CREATE SET e.name = ent.surname
      MERGE (e)-[:REGISTERED_ON]->(r)
      FOREACH(loc1 IN ent.entityLocationRelation |
        MERGE (l1:Locations {identity: loc1.locationIdentity})
        MERGE (e)-[:SEEN_AT]->(l1))
      FOREACH(ent2 IN ent.entityEntityRelation |
        MERGE (e2:Entities {identity: ent2.childIdentification})
        MERGE (e)-[:FRIENDS_WITH]->(e2))
    )
    FOREACH(loc IN data.locations |
      MERGE (l:Locations{identity:loc.identity})
      ON CREATE SET l.name = loc.city
      MERGE (l)-[:REGISTERED_ON]->(r)
    )
    
    为简单起见,它使用
    和关系类型上的注册对朋友进行硬编码,因为合并只支持硬编码关系类型

  • 变量名(如
    e
    r
    )不存储在数据库中,仅绑定到单个查询中的值<对具有未绑定变量的模式进行代码>合并只会创建整个模式(包括为未绑定节点变量创建空节点)

  • 创建节点时,应仅指定该节点的唯一标识属性,以避免重复。创建时要设置的任何其他属性都应使用“创建集”上的
    进行设置

  • 对JSON数据进行三次解析以获得数据的不同区域是低效的。而且查询的方式效率尤其低下,因为每个后续的
    调用/合并
    子句组都会执行多次(因为每个先前的
    调用
    都会生成多行,并且行数会成倍增加)。您可以使用来绕过这一点,但在您的情况下,这是不必要的,因为您可以在一次通过JSON数据的过程中完成整个查询

  • 这可能适用于您:

    CALL apoc.load.json(json_file,"$.JsonExport.*" ) YIELD value AS data
    MERGE(r:Registration {id:data.identification})
    FOREACH(ent IN data.entities |
      MERGE (e:Entities {identity: ent.identity})
      ON CREATE SET e.name = ent.surname
      MERGE (e)-[:REGISTERED_ON]->(r)
      FOREACH(loc1 IN ent.entityLocationRelation |
        MERGE (l1:Locations {identity: loc1.locationIdentity})
        MERGE (e)-[:SEEN_AT]->(l1))
      FOREACH(ent2 IN ent.entityEntityRelation |
        MERGE (e2:Entities {identity: ent2.childIdentification})
        MERGE (e)-[:FRIENDS_WITH]->(e2))
    )
    FOREACH(loc IN data.locations |
      MERGE (l:Locations{identity:loc.identity})
      ON CREATE SET l.name = loc.city
      MERGE (l)-[:REGISTERED_ON]->(r)
    )
    

    为简单起见,它使用
    和关系类型上的注册对朋友进行硬编码,因为合并只支持硬编码的关系类型。

    所以玩neo4j/cyper我学到了一些新东西,并找到了解决问题的另一种方法。基于给定的示例数据,以下内容可以动态创建节点和边

    WITH "file:///example.json" AS json_file
    CALL apoc.load.json(json_file,"$.JsonExport.*" ) YIELD value AS data
    CALL apoc.merge.node(['Registration'], {id:data.identification}, {},{}) YIELD node AS vReg
    
    UNWIND data.entities AS ent
      CALL apoc.merge.node(['Person'], {id:ent.identity}, {}, {id:ent.identity, surname:ent.surname}) YIELD node AS vPer1
        UNWIND ent.entityEntityRelation AS entRel
        CALL apoc.merge.node(['Person'],{id:entRel.childIdentification},{id:entRel.childIdentification},{}) YIELD node AS vPer2
        CALL apoc.merge.relationship(vPer1, entRel.typeRelation, {},{},vPer2) YIELD rel AS ePer
    
    UNWIND data.locations AS loc
      CALL apoc.merge.node(['Location'], {id:loc.identity}, {name:loc.city}) YIELD node AS vLoc
        UNWIND ent.entityLocationRelation AS locRel
        CALL apoc.merge.relationship(vPer1, locRel.typeRelation, {},{},vLoc) YIELD rel AS eLoc
    
    CALL apoc.merge.relationship(vLoc, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg1
    CALL apoc.merge.relationship(vPer1, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg2
    CALL apoc.merge.relationship(vPer2, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg3
    
    RETURN vPer1,vPer2, vReg, vLoc, eLoc, eReg1, eReg2, eReg3
    

    所以在玩neo4j/cyper时,我学到了一些新东西,并找到了解决问题的另一种方法。基于给定的示例数据,以下内容可以动态创建节点和边

    WITH "file:///example.json" AS json_file
    CALL apoc.load.json(json_file,"$.JsonExport.*" ) YIELD value AS data
    CALL apoc.merge.node(['Registration'], {id:data.identification}, {},{}) YIELD node AS vReg
    
    UNWIND data.entities AS ent
      CALL apoc.merge.node(['Person'], {id:ent.identity}, {}, {id:ent.identity, surname:ent.surname}) YIELD node AS vPer1
        UNWIND ent.entityEntityRelation AS entRel
        CALL apoc.merge.node(['Person'],{id:entRel.childIdentification},{id:entRel.childIdentification},{}) YIELD node AS vPer2
        CALL apoc.merge.relationship(vPer1, entRel.typeRelation, {},{},vPer2) YIELD rel AS ePer
    
    UNWIND data.locations AS loc
      CALL apoc.merge.node(['Location'], {id:loc.identity}, {name:loc.city}) YIELD node AS vLoc
        UNWIND ent.entityLocationRelation AS locRel
        CALL apoc.merge.relationship(vPer1, locRel.typeRelation, {},{},vLoc) YIELD rel AS eLoc
    
    CALL apoc.merge.relationship(vLoc, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg1
    CALL apoc.merge.relationship(vPer1, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg2
    CALL apoc.merge.relationship(vPer2, "REGISTERED_ON", {},{},vReg) YIELD rel AS eReg3
    
    RETURN vPer1,vPer2, vReg, vLoc, eLoc, eReg1, eReg2, eReg3
    

    谢谢你的回答!答案似乎并不完全正确(
    无法使用标识的null属性值合并节点)。可能与de JSON结构有关?但其背后的总体思路有些清晰。感谢您指出这一点,这有助于我继续前进!对于动态不动产,类似于
    apoc.create.relationship
    的内容将是一个选项,对吗?我修复了
    MERGE
    。现在应该可以工作了。很遗憾,您不能在
    FOREACH
    中调用过程。谢谢您的回答!答案似乎并不完全正确(
    无法使用标识的null属性值合并节点)。可能与de JSON结构有关?但其背后的总体思路有些清晰。感谢您指出这一点,这有助于我继续前进!对于动态不动产,类似于
    apoc.create.relationship
    的内容将是一个选项,对吗?我修复了
    MERGE
    。现在应该可以工作了。不幸的是,您不能在
    FOREACH
    中调用过程。