cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Create a new node for every attribute variable received from input json

Hello Everyone, I have a scenario to create new node for every attribute received as inputs . If the attribute already exists, need to update it or overwrite it . I have tried below cypher but it is creating new node for every record in the json Can someone help me to not create duplicate nodes

Input json:

:param emp: {"employees": [ {"eid":"1","key":"name","value":"xxx","action":"update"}, {"eid":"2","key":"sal","value":"1000","action":"update"}, {"eid":"2","key":"sal","value":"2000","action":"update"} ]}

Cypher I have tried :

WITH $emp AS inputs UNWIND inputs.employees as employee OPTIONAL MATCH (emp:Employee {eid:employee.eid}) WHERE exists(emp[employee.key]) WITH emp,employee CALL apoc.do.case([ emp IS NULL, "CREATE (emp1:Employee {eid:employee.eid}) SET emp1 += employee REMOVE emp1.key,emp1.value RETURN emp1 AS node",
(NOT emp IS NULL) AND exists(emp[employee.key]), "MATCH (emp) SET emp={}, emp += employee REMOVE emp1.key,emp1.value RETURN emp AS node"],
"RETURN {} AS node",
{emp:emp,employee: employee}) YIELD value WITH value.node as node1,employee CALL apoc.create.setProperty(node1, employee.key, employee.value) YIELD node return node

1 ACCEPTED SOLUTION

This turned out to be more challenging than I though up front. The issue with your query not working is due to the fact that the first match is first executed and then the resulting rows are processed. This means that you can't detect the new nodes as they are being created, thus the key part of your logic to match on an existing node with the same property does not work, thus you get more nodes than desired. 

What I did instead is merge all the data upfront to find the final combination of eid and key values, then create nodes for each. I assumed you wanted to take the last item in the list that had the same eid and key values, leaving that node. I used a map to perform the merge using a composite key of 'eid:key'. The resulting map then has the last employee in the list for each combination of eid and key. 

Is this what you wanted?

 

with [i in $employees | toString(i.eid) + ":" + toString(i.key)] as keys
with apoc.map.fromLists(keys, $employees) as map
unwind keys(map) as key
with map[key] as employee
with apoc.map.fromValues(['eid', employee.eid, employee.key, employee.value]) as props
create(n:Employee)
set n = props

 Result using your test data:

Screen Shot 2023-01-21 at 12.51.31 PM.png

View solution in original post

4 REPLIES 4

Yes, you code is creating only one node for each row in 'emp' list.  Can you describe what the multiple node should be for each element of 'amp'?  

For the below input , I would be expecting 5 nodes in the output


:params {
"employees": [
{ "eid":"1", "key":"name", "value": "test1" },
{ "eid":"1", "key":"name", "value": "test2" },
{ "eid":"2", "key":"name", "value": "test1" },
{ "eid":"1", "key":"name", "value": "test3" },
{ "eid":"3", "key":"name", "value": "test1" },
{ "eid":"2", "key":"name", "value": "test2" },
{ "eid":"2", "key":"sal", "value": "1000" },
{ "eid":"3", "key":"sal", "value": "3000" }
]
}

Output:

node1 - eid:"1",name:"test3"
node2 - eid:"2",name:"test2"
node3 - eid:"2",sal:"1000"
node4 - eid:"3",name:"test1"
node5 - eid:"3",sal:"3000"

This turned out to be more challenging than I though up front. The issue with your query not working is due to the fact that the first match is first executed and then the resulting rows are processed. This means that you can't detect the new nodes as they are being created, thus the key part of your logic to match on an existing node with the same property does not work, thus you get more nodes than desired. 

What I did instead is merge all the data upfront to find the final combination of eid and key values, then create nodes for each. I assumed you wanted to take the last item in the list that had the same eid and key values, leaving that node. I used a map to perform the merge using a composite key of 'eid:key'. The resulting map then has the last employee in the list for each combination of eid and key. 

Is this what you wanted?

 

with [i in $employees | toString(i.eid) + ":" + toString(i.key)] as keys
with apoc.map.fromLists(keys, $employees) as map
unwind keys(map) as key
with map[key] as employee
with apoc.map.fromValues(['eid', employee.eid, employee.key, employee.value]) as props
create(n:Employee)
set n = props

 Result using your test data:

Screen Shot 2023-01-21 at 12.51.31 PM.png

Thank you glilienfield, It is working fine