Search code examples
neo4jcypher

How to make nodes and form n to m relationship in neo4j when given 'm' data is constructed in one csv column?


I want to design a database in neo4j where I want to make nodes and relationships between other nodes. To explain it neatly please consider following scenario:

From given csv file one column represents unique IDs and another column represents classes, where in some class column there is only one class whereas in many column there are many classes.

i.e.

---------------------
|  ID   |  Class    |
---------------------
|  ID1  |  Class-A  |
---------------------
|  ID2  |  Class-A  |
|       |  Class-B  |
|       |  Class-C  |
---------------------

From the above example data, the query must generate (ID1) node and (Class-A) node with HAS relationship. Same with ID2. (ID2)--[HAS]-->(Class-A) , (ID2)--[HAS]-->(Class-B) and so on.

I was able to write following query.

load csv with headers from 'path' as line
match(id:ID{id:line.ID}), (temp:TEMP{id:line.Class})
    with temp, split(temp.id, " ") as ids
    unwind range(0,size(ids)-1) as i
merge(id)-[n:HAS]->(class:CLASS{id:ids[i]})
delete temp
return n

I am able to create individual nodes from Class column, but it creates relationships with empty nodes and not with associated IDs.

Any lead would be great help.

I am new to database design. Thanks


Solution

  • You need to carefully read the MERGE clause documentation, as it is easy to use incorrectly and get unexpected results. For example, individual nodes and relationships should always be MERGEd separately.

    Also, since your query MATCHes Id nodes at the outset, all Id nodes mentioned in the CSV file must already exist, or else some lines will do nothing. It is not clear if that is intentional.

    Here is a query that should work as expected (and create Id nodes as necessary). Note that I changed the node labels to mixed case to match the standard neo4j naming convention. Also, there is no need for a temporary node.

    LOAD CSV WITH HEADERS FROM 'path' AS line
    MERGE (id:Id {id: line.ID})
    WITH line, id
    UNWIND SPLIT(line.Class, " ") AS cId
    MERGE (class:Class {id: cId})
    MERGE (id)-[r:HAS]->(class)
    RETURN r