Reputation: 141
I'm trying to fix up incorrect data in my Neo4j database, and I'd like to have just a cypher to do the updating rather than transferring millions of rows to a custom application and back.
I've created a Read query that's using dynamic keys to search through every property on all nodes of a labels I specify for various types of issues - in this case, an incorrectly serialized string. The issue I'm running into is that while the Read query using dynamic keys works great:
MATCH (n:xLabelNamex)
WITH
n,
[x IN keys(n)
WHERE n[x] STARTS WITH "\""
AND n[x] ENDS WITH "\""
] AS doesMatch
WHERE size(doesMatch) > 0
UNWIND doesMatch AS label
MATCH (m:xLabelNamex)
WHERE id(n)=id(m)
RETURN SUBSTRING(m[label], 1, SIZE(m[label]) - 2)
But if I leave everything the same, and change the last line from
RETURN SUBSTRING(m[label], 1, SIZE(m[label]) - 2)
to:
SET m[label] = SUBSTRING(m[label], 1, length(m[label]) - 2)
Results in the error:
Invalid input '[': expected an identifier character, node labels, a property map, whitespace, a relationship pattern, '(', '.', '=' or "+=" (line 12, column 10 (offset: 255))
" SET m[label] = SUBSTRING(m[label], 1, SIZE(m[label]) - 2)"
^
Is there a way to do this, or am I going down the wrong road here?
Looking at the discussions on Github, I see that the addition of the reading of nodes using dynamic keys was added a little over a year ago, but it looks like they made it specifically targeted towards Read only. I started digging through Neo's source, but it's a behemoth. Any help would be appreciated.
Upvotes: 0
Views: 1661
Reputation: 141
For anyone coming in after this, the library Tore suggested - APOC - just released version 3.0.4.2 which introduced "apoc.create.setProperty", and does exactly what I need. Additionally, I found that regexes are MUCH faster in Neo4j than straight text searches (one order of magnitude faster), so I went with that as well.
My final cypher came out to be:
MATCH (n:xLabelNamex)
WITH
n,
[x IN keys(n)
WHERE n[x] =~ '".*"'
] AS doesMatch
WHERE size(doesMatch) > 0
UNWIND doesMatch AS label
MATCH (m:xLabelNamex)
WHERE id(n)=id(m)
CALL apoc.create.setProperty(m, label, SUBSTRING(m[label], 1, SIZE(m[label]) - 2))
YIELD node
RETURN node
Works like a charm.
Props to Tore, thank you again!
Upvotes: 1