Search code examples
restneo4jcypheridempotent

Trying to create an idempotent Cypher query


So, I have been fighting cypher for the last week trying to get an idempotent query that deletes all of a type of node attached to a given root, then creates only as many nodes as are in the parameters. The problem is that either delete won't actually delete anything, or the nodes start multiplying at a dizzying rate every time I perform the query. One iteration managed to create over 10000 duplicate nodes before failing. I'm attempting to use this for a PUT request in a REST API. I'm working in Node.js with the Seraph library, but I'm just using the basic cypher query it provides.

Here's the most recent iteration of the query:

  var query = " MATCH (title:TITLE {sku: {sku}})" +
" OPTIONAL MATCH (title)-[r_GTIN]->(old_GTIN:GTIN)" +
" WITH title, r_GTIN, old_GTIN" +
" DELETE r_GTIN, old_GTIN" +
" WITH title" +
" CREATE (gtin:GTIN {gtins})" +
" MERGE (title)-[:has_GTIN]->(gtin);";

And here are example params:

{
sku: "ABC12345"
gtins: [{number: "999-999-999", type: "firstKind"},
        {number: "888-888-888", type: "secondKind"},
        {number: "777-777-777", type: "thirdKind"}]
}

I've tried more variations on this than I care to recount.


Solution

  • I was able to take your query and modify it slightly and have it execute what I think you are after. The difference is after the nodes are deleted only the distinct title is passed onto the next clause in the query.

    Without the distinct you pass potentially multiple matches of the same title node to the create clause in your query thus causing the same nodes to be created many times.

    with [{number: "999-999-999", type: "firstKind"},
     {number: "888-888-888", type: "secondKind"},
     {number: "777-777-777", type: "thirdKind"}] as new_gtins
    match (title:TITLE {sku: 'ABC12345'})
    optional match title-[r:has_GTIN]->(gtin:GTIN)
    delete r, gtin
    with distinct title as title, new_gtins 
    unwind new_gtins as new_gtin
    create title-[:has_GTIN]->(gtin:GTIN {type: new_gtin.type, number: new_gtin.number})