Changes to Context Flow Variable also changes source array it was extracted from

I have found what I think is anomalous behavior (from what I expected) when changing an element in a context Flow Object Variable that was itself extracted as one object in an array of objects from a object in Context Flow variables.

To explain further as demonstrated in this Flow. We create a array of JSON objects flow.sZones. From that we extract one object from the array into flow.sZone = flow.sZones.Zone[4].

Now I change one element in flow.sZone to a new value but it also changes the corresponding value in flow.sZones, it even gets the right element. As demonstrated in flow below I change flow.sZone.Value = 23 but this also changes flow.sZones.Zone[4].Value to 23.
It is like flow.sZone is not a separate variable, but a pointer to flow.sZones.Zone[4]

[{"id":"97d95e4.9c88aa","type":"inject","z":"c3c6cf1d.d7dd1","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":124.5,"y":60,"wires":[["50e4695e.fd9688"]]},{"id":"50e4695e.fd9688","type":"change","z":"c3c6cf1d.d7dd1","name":"Reset Array","rules":[{"t":"set","p":"sZones","pt":"flow","to":"{\"Zone\":[{\"Number\":0,\"Name\":\"Zero\",\"Description\":\"D Zero\",\"Value\":4},{\"Number\":1,\"Name\":\"One\",\"Description\":\"D One\",\"Value\":5},{\"Number\":2,\"Name\":\"Two\",\"Description\":\"D Two\",\"Value\":6},{\"Number\":3,\"Name\":\"Three\",\"Description\":\"D Three\",\"Value\":7},{\"Number\":4,\"Name\":\"Four\",\"Description\":\"D Four\",\"Value\":8},{\"Number\":5,\"Name\":\"Five\",\"Description\":\"D Five\",\"Value\":9},{\"Number\":6,\"Name\":\"Six\",\"Description\":\"D Six\",\"Value\":10},{\"Number\":7,\"Name\":\"Seven\",\"Description\":\"D Seven\",\"Value\":11}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":326.5,"y":60,"wires":[["9497f5fa.3bb0e8"]]},{"id":"9497f5fa.3bb0e8","type":"change","z":"c3c6cf1d.d7dd1","name":"","rules":[{"t":"set","p":"sZone","pt":"flow","to":"sZones.Zone[4]","tot":"flow"},{"t":"set","p":"sZone.Value","pt":"flow","to":"23","tot":"num"},{"t":"set","p":"sZones","pt":"msg","to":"sZones","tot":"flow"},{"t":"set","p":"sZone","pt":"msg","to":"sZone","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":637,"y":60,"wires":[["827be915.44bbc8"]]},{"id":"827be915.44bbc8","type":"debug","z":"c3c6cf1d.d7dd1","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":801.5,"y":60,"wires":[]}]

Latest Nod-Red (1.02) running on up to date W10 (my Sandpit). Context Variables in memory only

You have discovered JavaScript object references. :slight_smile:

This behaviour is normal and has been covered a few times though I'm not sure how you would search this subject.

This may help explain, read to last post

Interesting that it defaults to Object reference instead of a new Object as I would have expected as default (being a C++ programmer, if I wanted a reference, I would have used a pointer variable).

I have tried to create flow.sZone through a message variable (msg.sZones) hoping for a copy not a Reference but nogo.

But I need to need to create a independent copy of the array object, for a ui to that allows the elements of the object to be changed, but the Array (flow.sZones) is not to be updated until the update button is pressed and the new values checked for compatibility (more than range checks).

So is there a way (without diving into function Nodes and Java Script) to create flow.sZone as a COPY of one element of the flow.Zones array instead of a reference?

In a function node, you can use RED.util.cloneMessage(obj) to create a copy of the object, and then work with that copy down the path.

You can convert the flow.sZones object to a JSON string and back again to effectively make a copy of the object without having to use Javascript in a function

[{"id":"d38dcbbe.bef888","type":"inject","z":"a749dae7.2dd888","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":192,"y":396,"wires":[["e760dd3c.5b70d"]]},{"id":"e760dd3c.5b70d","type":"change","z":"a749dae7.2dd888","name":"Reset Array","rules":[{"t":"set","p":"sZones","pt":"flow","to":"{\"Zone\":[{\"Number\":0,\"Name\":\"Zero\",\"Description\":\"D Zero\",\"Value\":4},{\"Number\":1,\"Name\":\"One\",\"Description\":\"D One\",\"Value\":5},{\"Number\":2,\"Name\":\"Two\",\"Description\":\"D Two\",\"Value\":6},{\"Number\":3,\"Name\":\"Three\",\"Description\":\"D Three\",\"Value\":7},{\"Number\":4,\"Name\":\"Four\",\"Description\":\"D Four\",\"Value\":8},{\"Number\":5,\"Name\":\"Five\",\"Description\":\"D Five\",\"Value\":9},{\"Number\":6,\"Name\":\"Six\",\"Description\":\"D Six\",\"Value\":10},{\"Number\":7,\"Name\":\"Seven\",\"Description\":\"D Seven\",\"Value\":11}]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":334,"y":396,"wires":[["46f6827b.b539dc"]]},{"id":"cbd14ffe.acb51","type":"change","z":"a749dae7.2dd888","name":"","rules":[{"t":"set","p":"sZone","pt":"flow","to":"payload.Zone[4]","tot":"msg"},{"t":"set","p":"sZone.Value","pt":"flow","to":"23","tot":"num"},{"t":"set","p":"sZones","pt":"msg","to":"sZones","tot":"flow"},{"t":"set","p":"sZone","pt":"msg","to":"sZone","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":982,"y":396,"wires":[["700d6cba.09c2b4"]]},{"id":"700d6cba.09c2b4","type":"debug","z":"a749dae7.2dd888","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1172,"y":396,"wires":[]},{"id":"9358d642.e740d8","type":"json","z":"a749dae7.2dd888","name":"","property":"payload","action":"str","pretty":false,"x":688,"y":440,"wires":[["76c45d1e.b87d84"]]},{"id":"46f6827b.b539dc","type":"change","z":"a749dae7.2dd888","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"sZones","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":542,"y":440,"wires":[["9358d642.e740d8"]]},{"id":"76c45d1e.b87d84","type":"json","z":"a749dae7.2dd888","name":"","property":"payload","action":"obj","pretty":false,"x":798,"y":440,"wires":[["cbd14ffe.acb51"]]}]
1 Like

Thanks all, I have just resorted to the solution using a function Node to create the Copy as Node-red has no means in change nodes to discriminate a copy from a reference...maybe something for the future.
Passed on the idea of json nodes conversion via a string... neat but experience is something in data will break it oneday, when I have forgotten what I was doing.

Sounds like an easy subflow at that too to bundle the functionality in a single node:

[{"id":"a74810ad.572d68","type":"subflow","name":"Safely clone payload","info":"","category":"","in":[{"x":40,"y":100,"wires":[{"id":"9902e680.b70428"}]}],"out":[{"x":440,"y":100,"wires":[{"id":"7c2a719c.8f8ec","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"9902e680.b70428","type":"json","z":"a74810ad.572d68","name":"","property":"payload","action":"","pretty":false,"x":160,"y":100,"wires":[["7c2a719c.8f8ec"]]},{"id":"7c2a719c.8f8ec","type":"json","z":"a74810ad.572d68","name":"","property":"payload","action":"","pretty":false,"x":300,"y":100,"wires":[[]]},{"id":"e6e6f20.1bc521","type":"subflow:a74810ad.572d68","z":"fb5ea0b2.375b88","name":"","x":770,"y":320,"wires":[[]]}]
2 Likes

Well, I believe conversion between JS Objects and JSON is a very tried and tested process and it does meet your original criteria :slight_smile:

:slight_smile:

@IanH,
Here is an exemple of RED.util.cloneMessage(obj) you can play with, and look at the illustration in a graph.
You can remove the 'clonemessage' in the 2nd function node to see what happens.
regards

[{"id":"e2d94b24.73a818","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"a586fda0.3331d","type":"function","z":"e2d94b24.73a818","name":"","func":"var obj= flow.get(\"obj\") || {'value' : null};\nvar obj15= flow.get(\"obj15\") || {'value' : null};\n\nobj.value += Math.round(Math.random() * 1000);\n\nflow.set (\"obj\", obj);\nvar msg0={}; var msg1={};\nmsg0.payload = obj.value;\nmsg0.topic = 'obj';\nmsg1.payload = obj15.value;\nmsg1.topic = 'obj15';\n\nreturn [msg0, msg1];","outputs":2,"noerr":0,"x":330,"y":300,"wires":[["7187fcfa.07a69c","907a8e9e.89f7e","dceff6d.a05f488"],["7187fcfa.07a69c","907a8e9e.89f7e"]]},{"id":"7187fcfa.07a69c","type":"debug","z":"e2d94b24.73a818","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":530,"y":220,"wires":[]},{"id":"19b468d9.20b2d7","type":"inject","z":"e2d94b24.73a818","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":0.1,"x":150,"y":300,"wires":[["a586fda0.3331d"]]},{"id":"907a8e9e.89f7e","type":"ui_chart","z":"e2d94b24.73a818","name":"","group":"fd99b7e9.b69f1","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"40","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#ff7f0e","#d62728","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":970,"y":420,"wires":[[]]},{"id":"23dc6be4.f00aa4","type":"function","z":"e2d94b24.73a818","name":"","func":"\nvar obj= RED.util.cloneMessage(flow.get(\"obj\")) || {'value' : null}; //RED.util.cloneMessage(flow.get(\n\n\nflow.set (\"obj15\", obj);\nmsg.payload = obj.value + 1000;\nmsg.topic = \"obj15+1000\";\n\nreturn msg;","outputs":1,"noerr":0,"x":720,"y":300,"wires":[["907a8e9e.89f7e"]]},{"id":"dceff6d.a05f488","type":"delay","z":"e2d94b24.73a818","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"15","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":540,"y":300,"wires":[["23dc6be4.f00aa4"]]},{"id":"bfb13a8f.b61798","type":"debug","z":"e2d94b24.73a818","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":460,"wires":[]},{"id":"1a56a595.e7e792","type":"change","z":"e2d94b24.73a818","name":"","rules":[{"t":"delete","p":"obj","pt":"flow"},{"t":"delete","p":"obj15","pt":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":200,"wires":[[]]},{"id":"d6f15234.5125c","type":"inject","z":"e2d94b24.73a818","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":200,"wires":[["1a56a595.e7e792"]]},{"id":"fd99b7e9.b69f1","type":"ui_group","z":"","name":"Default","tab":"f9641994.610e8","disp":true,"width":"6","collapse":false},{"id":"f9641994.610e8","type":"ui_tab","z":"","name":"Flow1","icon":"dashboard","disabled":false,"hidden":false}]