Global Variable being overwritten without global.set

I have been using node red for quite a while and have run into an issue I have never seen.

I am pulling in an array from a server and saving it as a global variable using a change node.

This works as expected, the array saves as the variable.

However it is being overwritten for some reason in a function block that never uses global.set. Has anyone seen this before?

Inject node -> change node (setting its payload to the global variable array I saved from the server) ->Function block with the following code:

BT = global.get("BackTestSMA21")
Test = msg.payload;
c = Test.c.slice(0,BT);
v = Test.v.slice(0,BT);
return msg;

the "BackTestSMA21" global is simply an incrementing number I am using to output parts of the big array I have grabbed from the server.

I don't understand how this function block would ever change that first global variable. Any suggestions are greatly appreciated.

Javascript uses references for objects, so when you set BT to the global you set a reference to the global. Then when you alter BT you you also change the global that it references.
best to clone the global object BT = RED.util.cloneMessage(global.get("BackTestSMA21"))
https://nodered.org/docs/api/modules/v/0.20.0/@node-red_util_util.html#.cloneMessage

[edit] On a second look at your post, the code you show would not do that, maybe some other function is doing it.

Thank you for the input, it is definitely happening in this function block, I was able to narrow it down to this function block, I don't even reference the main array global anywhere else, and did a quick test of disabling this function block to prove it out.

It's super weird behavior I've never had this issue before.

Are you certain that is the full function code? It doesn't do anything at all. You grab a global "thing" then make 2 slices on a passed in objects properties .c and .v. But you don't do anything with them. So if that is not the full function, do you pass c and v to other nodes?. Because that's where I guess the"damage" would happen (since the slices are references)

I am doing more with that function block, but even just that little bit appeared to change the global that was being fed in.

BT = global.get("BackTestSMA21")
Test = msg.payload;
c = Test.c.slice(0,BT);
h = Test.h.slice(0,BT);
l = Test.l.slice(0,BT);
o = Test.o.slice(0,BT);
sma = Test.sma.slice(0,BT);
t = Test.t.slice(0,BT);
v = Test.v.slice(0,BT);
msg.payload.c = c;
msg.payload.h = h;
msg.payload.l = l;
msg.payload.o = o;
msg.payload.sma = sma;
msg.payload.t = t;
msg.payload.v = v;
//msg.payload = Test;
return msg;

Basically all I am trying to do is

read in a large object from a server that has all of these properties.
Save the whole object as a global
slice the individual properties sequentially to give me smaller versions of those arrays.

so the server gives me one message object like the below, but much larger:

{
"c": [
206,
205.4,
204.8,
204.5,
203.5,
],
"h": [
206,
205.6,
204.8,
204.5,
203.5,
],
"l": [
206,
205.4,
204.8,
204.5,
203.5,
],
"o": [
206,
205.6,
204.8,
204.5,
203.5,
],
"s": "ok",
"sma": [
0,
0,
0,
0,
0,
],
"t": [
1616151720,
1616151780,
1616151840,
1616151900,
1616151960,
],
"v": [
255,
1700,
810,
537,
430,
]
}

I want to slice all of these arrays into smaller arrays, rejoin them into the full object, and pass the new smaller array getting larger in size by 1 on every message from the inject node.

so one of the initial arrays, take c for example:

"c": [206,205.4,204.8,204.5,203.5] This would be inside the global "Main" array

I want to pull that main array (right now I am pulling it through a change node and feeding it to the function block above) and slice it to push out objects where all of the arrays are increasing until it finally pushes out the entirety of the first object.

so the first pass of the function block would output
"c": [206]
then
"c": [206,205.4]
then
"c": [206,205.4,204.8]

and so on.

There may be a much easier way of accomplishing this, I am just confused why this function block would ever overwrite that first global.

The only two blocks that reference that global are when I global.set it from the GET command for the server, and when I global.get the array to feed into this function block

[
    {
        "id": "95283eaf.abcaf",
        "type": "inject",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 570,
        "y": 240,
        "wires": [
            [
                "2674a71b.6a8ca8"
            ]
        ]
    },
    {
        "id": "2674a71b.6a8ca8",
        "type": "function",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "func": "msg.payload =\n{\n  \"c\": [\n    206,\n    205.4,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"h\": [\n    206,\n    205.6,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"l\": [\n    206,\n    205.4,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"o\": [\n    206,\n    205.6,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"s\": \"ok\",\n  \"sma\": [\n    0,\n    0,\n    0,\n    0,\n    0,\n  ],\n  \"t\": [\n    1616151720,\n    1616151780,\n    1616151840,\n    1616151900,\n    1616151960,\n  ],\n  \"v\": [\n    255,\n    1700,\n    810,\n    537,\n    430,\n  ]\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 750,
        "y": 240,
        "wires": [
            [
                "1437a94f.c29b07",
                "89d665a6.48fff8"
            ]
        ]
    },
    {
        "id": "1437a94f.c29b07",
        "type": "change",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "mainArray",
                "pt": "global",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 970,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "fff9179b.7408b8",
        "type": "function",
        "z": "3e144ca1.3f13a4",
        "name": "SMA21",
        "func": "BT = global.get(\"BackTestSMA21\")\nTest = msg.payload;\nc = Test.c.slice(0,BT);\nh = Test.h.slice(0,BT);\nl = Test.l.slice(0,BT);\no = Test.o.slice(0,BT);\nsma = Test.sma.slice(0,BT);\nt = Test.t.slice(0,BT);\nv = Test.v.slice(0,BT);\nmsg.payload.c = c;\nmsg.payload.h = h;\nmsg.payload.l = l;\nmsg.payload.o = o;\nmsg.payload.sma = sma;\nmsg.payload.t = t;\nmsg.payload.v = v;\n//msg.payload = Test;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 910,
        "y": 380,
        "wires": [
            [
                "39e521af.58e7be"
            ]
        ]
    },
    {
        "id": "6860c307.f3af4c",
        "type": "function",
        "z": "3e144ca1.3f13a4",
        "name": "Array Step through",
        "func": "BackTestOld = global.get(\"BackTestSMA21\");\nif (BackTestOld <= 1){\nBackTestNew = BackTestOld+1;\nglobal.set(\"BackTestSMA21\",BackTestNew);\nmsg.payload = BackTestNew;\nreturn msg;\n}\nif (BackTestOld >= 0){\nmsg.payload = \"close\";\nmsg.topic = \"control\";\nreturn msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 820,
        "y": 320,
        "wires": [
            [
                "2d8b5d74.f7f912"
            ]
        ]
    },
    {
        "id": "2d8b5d74.f7f912",
        "type": "change",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "mainArray",
                "tot": "global"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1030,
        "y": 320,
        "wires": [
            [
                "fff9179b.7408b8"
            ]
        ]
    },
    {
        "id": "76b47e67.48d15",
        "type": "inject",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": true,
        "onceDelay": "5",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 540,
        "y": 320,
        "wires": [
            [
                "6860c307.f3af4c"
            ]
        ]
    },
    {
        "id": "89d665a6.48fff8",
        "type": "function",
        "z": "3e144ca1.3f13a4",
        "name": "BackTest global",
        "func": "BackTest = msg.payload.sma.length;\nMinus = -BackTest+1;\nglobal.set(\"BackTestSMA21\", Minus);\nmsg.payload = BackTest;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 970,
        "y": 180,
        "wires": [
            []
        ]
    },
    {
        "id": "677a5530.c8e86c",
        "type": "debug",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1290,
        "y": 180,
        "wires": []
    },
    {
        "id": "39e521af.58e7be",
        "type": "change",
        "z": "3e144ca1.3f13a4",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "mainArray",
                "tot": "global"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1100,
        "y": 380,
        "wires": [
            [
                "677a5530.c8e86c"
            ]
        ]
    }
]

Here is a sample flow using that smaller object from above that looks to be behaving the same, writing over the mainArray global

As I suspected, there was more to your function than that little bit of code you provided in the first post.

What's happening is when you (in the change node) SET msg.payload to global.mainArray - you actually set a reference (in msg.payload) to the global.mainArray (they are at this point, the very same thing). Then inside your function, after slicing .c you set msg.payload.c to the sliced array. As @E1cid said earlier, in JS, arrays and objects are references so when you update msg.payload.c with the smaller slice, you actually update global.mainArray.


The solution (there are many).

Assuming i read your requirement correctly, this is the output...

This is the flow...

[{"id":"95283eaf.abcaf","type":"inject","z":"8c0d4c46.2bfb5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":310,"y":896,"wires":[["2674a71b.6a8ca8"]]},{"id":"2674a71b.6a8ca8","type":"function","z":"8c0d4c46.2bfb5","name":"","func":"msg.payload =\n{\n  \"c\": [\n    206,\n    205.4,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"h\": [\n    206,\n    205.6,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"l\": [\n    206,\n    205.4,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"o\": [\n    206,\n    205.6,\n    204.8,\n    204.5,\n    203.5,\n  ],\n  \"s\": \"ok\",\n  \"sma\": [\n    0,\n    0,\n    0,\n    0,\n    0,\n  ],\n  \"t\": [\n    1616151720,\n    1616151780,\n    1616151840,\n    1616151900,\n    1616151960,\n  ],\n  \"v\": [\n    255,\n    1700,\n    810,\n    537,\n    430,\n  ]\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":896,"wires":[["1437a94f.c29b07"]]},{"id":"1437a94f.c29b07","type":"change","z":"8c0d4c46.2bfb5","name":"","rules":[{"t":"set","p":"mainArray","pt":"global","to":"payload","tot":"msg"},{"t":"set","p":"BackTestSMA21","pt":"global","to":"payload.sma.length","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":690,"y":896,"wires":[[]]},{"id":"fff9179b.7408b8","type":"function","z":"8c0d4c46.2bfb5","name":"SMA21","func":"var mainArray = RED.util.cloneMessage( global.get(\"mainArray\") );\nvar BT = global.get(\"BackTestSMA21\") || 0;\n\nif (BT > 0){\n    BT--;\n    global.set(\"BackTestSMA21\", BT);\n} else {\n    return null;\n}\n\nfunction getsome(arr, size) {\n    if (size == 0) return arr;\n    return arr.slice(0,-BT)\n}\n\n\nmsg.payload = {\n    c : getsome(mainArray.c, -BT),\n    h : getsome(mainArray.h, -BT),\n    l : getsome(mainArray.l, -BT),\n    o : getsome(mainArray.o, -BT),\n    sma : getsome(mainArray.sma, -BT),\n    t : getsome(mainArray.t, -BT)\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":492,"y":976,"wires":[["677a5530.c8e86c"]]},{"id":"76b47e67.48d15","type":"inject","z":"8c0d4c46.2bfb5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"5","topic":"","payload":"","payloadType":"date","x":300,"y":976,"wires":[["fff9179b.7408b8"]]},{"id":"677a5530.c8e86c","type":"debug","z":"8c0d4c46.2bfb5","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":694,"y":976,"wires":[]}]

Wow, learning something new everyday.

Thanks for your help y'all!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.