How to access and mutate node property value by the property name string in Cypher?
cypher, graph-databases, neo4j, reflection
Solution
It appears that the desired language feature was added to Cypher in Neo4j 2.3.0 under the name "dynamic property". The Cypher docs from version 2.3.0-up declare the following syntax group as a valid cypher expression:
A dynamic property: `n["prop"]`, `rel[n.city + n.zip]`, `map[coll[0]]`.
This feature is documented for 2.3.0 but is absent from the previous version (2.2.9).
Thank you Neo4j Team!
Problem
My goal is to access and mutate a property of a node in a cypher query where the name of the property to be accessed and mutated is an unknown string value. For example, consider a command: Find all nodes containing a two properties such that the name of the first property is lower-case and the name of the latter is the upper-case representation of the former. Then, propagate the value of the property with the lower-case string name to the value of the property with the upper-case name. The particular case is easy: ``` MATCH ( node ) WHERE has(node.age) AND has(node.AGE) AND node.age <> node.AGE SET node.AGE = node.age RETURN node; ``` But I can't seem to find a way to implement the general case in a single request. Specifically, I am unable to: - Access the property of the node with a string and a value - Mutate the property of the node with a string and a value For the sake of clarity, I'll include my attempt to handle the general case. Where I failed to modify the property of the node I was able to generate the cypher for a command that would accomplish my end goal if it were executed in a subsequent transaction. ``` MERGE ( justToMakeSureOneExists { age: 14, AGE : 140 } ) WITH justToMakeSureOneExists MATCH (node) WHERE ANY ( kx IN keys(node) WHERE kx = LOWER(kx) AND ANY ( ky in keys(node) WHERE ky = UPPER(kx) ) ) REMOVE node.name_conflicts // make sure results are current FOREACH(kx in keys(node) | SET node.name_conflicts = COALESCE(node.name_conflicts,[]) + CASE kx WHEN lower(kx) THEN [] + CASE WHEN any ( ky in keys(node) WHERE ky = upper(kx) ) THEN ['match (node) where id(node) = ' + id(node)+ ' and node.' + upper(kx) + ' <> node.' + kx + ' set node.' + upper(kx) + ' = node.' + kx + ' return node;'] ELSE [] END ELSE [] END ) RETURN node,keys(node) ``` Afterthought: It seems like the ability to mutate a node property by property name would be a pretty common requirement, but the lack of obvious support for the feature leads me to believe that the feature was omitted deliberately? If this feature is indeed unsupported is there any documentation to explain why and if there is some conflict between the approach and the recommended way of doing things in Neo/Cypher?