Search code examples
foreachneo4jpy2neo

Creating unique relationship property in a FOREACH in neo4j


I am trying to accomplish something quite simple in python but not so in Neo4j. I'd appreciate any comment and suggestions to improve the procedure!

Within Python script, I am trying to create a relationship as well as its property for every pair of two nodes. From a data analysis (not a csv file), I ended up having a dataframe with three columns as following:

name1    name2    points
===========================
Jack     Sara     0.3
Jack     Sam      0.4
Jack     Jill     0.2
Mike     Jack     0.4
Mike     Sara     0.5    
...

From this point, I would like to create all nodes for the people: Jack, Sara, Sam, Mike, etc and as well as their relationship with a property name points.

First I tried to match all nodes and then use "FOREACH" to update the relationship property one at a time.

tx = graph.cypher.begin()
qs2 = "MATCH (p1:person {name:"Jack"}), (p2:person) 
       WHERE p2.name IN ["Sara","Jill","Mike"] 
       FOREACH (r IN range(10) | 
         CREATE (p1)-[:OWES TO {score:{score_list}[r]}]->(p2))"

Above statement does not return what I expected. Instead of matching one node to another, it calls all nodes in p2 and create the relationship between the paris, resulting multiple copies of the same information.

Is there a notation to indicate one node at a time? If you think there is a better approach than above, please do share with me. Thank you!


Solution

  • The easiest approach would be to export the data to be imported into csv file and use then the LOAD CSV command in cypher.

    LOAD CSV WITH HEADERS FROM <url> AS csvLine
    MATCH (p1:Person {name:csvLine.name1}), (p2:Person {name:csvLine.name2})
    CREATE (p1)-[:OWES_TO {score:csvLine.points}]->(p2)
    

    In case you cannot use that approach you can use a parameterized Cypher statement using the transactional http endpoint. The parameter is a single element map containing an array of your data structure. On http level the request body would look like:

    {
       "statements": [
           {
               "parameters": {
                   "data": [
                       {
                           "name1": "Jack", "name2": "Sara", "points": 0.3 
                       }, 
                       {
                           "name1": "Jack", "name2": "Sam", "points": 0.4
                       }, 
                       {
                           "name1": "Jack", "name2": "Jill", "points": 0.2
                       }  // ...
                   ]
               }, 
               "statement": "UNWIND {data} AS row     
                             MATCH (p1:Person {name:row.name1}), (p2:Person {name:row.name2})
                             CREATE (p1)-[:OWES_TO {row.points}]->(p2)"
           }
       ]
    }
    

    update regarding comment below

    Q: How can I create the parameters from pyhton? A: use the python json module

    import json
    json.dumps({'data':[{'name1':'Jack', 'name2':'Sara', 'points':0.3},{'name1':'Jack', 'name2':'Sam', 'points':0.4}]})