Global numeric array trouble using global get and set

Can someone help? I need a simple array humidityArray with 24 values. Every hour I would move offset 22 value into offset 23, 21 into 22 etc.... and put latest value into offset zero... so I would always be able tot total all 24 values once a day and didide that by 24 to give me the daily average humidity... except it isn't working. I'm assuming it is something to do with defining/initialising the array which happens when node red powers up... this should be a simple calculation but a day later I can't get offset value above offset 2 to fill in. I initialise all 24 offsets to -1 when node red powers up... that much seems to work.

offset 0 gets the latest value and next iteration this should get shoved up one with the oldest value falling off the end.

Someone please put me out of my misery.

Hi @scargill,

You can use the Array.unshift function to push new items onto the front of the Array.
You can then use Array.slice to ensure its no more than 24 elements long.

Assuming the new value is in msg.payload:

humidityArray.unshift(msg.payload);
humidityArray = humidityArray.slice(0,24);

Good Nick but apparently not. This is a global array.. hence your version says humidityArray is not defined.

Peter,
could you provide the code or flow where you are doing this? could you use a function node to move the global to a local, do the unshift/slice and then move it back to the global?

Try this flow:

[{"id":"f0f3fd73.1c396","type":"function","z":"12f1321f.454d1e","name":"hum array","func":"var hum = global.get('hum') || [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23];\n\nhum.unshift(msg.payload);\nhum.splice(24, 1);\n\nmsg.payload=hum;\nglobal.set('hum',hum);\n\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":120,"wires":[["ea00bc55.eddb2"]]},{"id":"d6547d88.1430f","type":"inject","z":"12f1321f.454d1e","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":120,"wires":[["e8392f2d.46568"]]},{"id":"ea00bc55.eddb2","type":"debug","z":"12f1321f.454d1e","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":610,"y":120,"wires":[]},{"id":"e8392f2d.46568","type":"random","z":"12f1321f.454d1e","name":"","low":"20","high":"80","inte":"true","property":"payload","x":280,"y":120,"wires":[["f0f3fd73.1c396"]]}]
1 Like

In your original post you said you had an array called humidityArray - I've shown you how to operate on that array on the assumption you already have it in scope of your Function.

I've assumed you know how to get/set something from global context - but here's the same code with the extra bits to do that:

var humidityArray = global.get("humidityArray")||[];
humidityArray.unshift(msg.payload);
humidityArray = humidityArray.slice(0,24);
global.set("humidityArray",humidityArray);
return msg;

I did thanks, I put it into a local array and back and that works a treat. But that does not explain why I can’t manipulate the global. Just rewrote the code to use the local.

Thanks, solved by using local var.

Is that necessary? I would have expected that after the global.get then the local variable would refer to the same array as the global, therefore manipulating the local will also manipulate the global, and therefore one should be able to do

global.get("humidityArray").unshift(msg.payload);

Sorry I was trying to operate on the global array. I still don’t understand why that does not work but thanks to your input and that from others, I’m operating on a local copy. Just seems like an inconsistent extra step as I operate on globals without issue otherwise.

Regards

Pete

As far as I know this is the case when passing an object to a function but not with global.get() so you have to use global.set();

If you don't need a global, it's anyway better to use a local var.
edit: ignore it!

Can you provide an example of what you mean by this?

What I've shared is what I would describe as 'operating on globals' ... so would like to understand what you mean by that.

You take advantage of an implementation detail of how context is stored in memory.

With the next release, if you enable the new file based persistence, that will not work as the value stored on disk will not get updated without a call to set.

Ok, now I’m even more confused. Can someone confirm or otherwise what Colin is saying? If so then writing back to the global is wasting time?

None of which explains why I can’t just work on the global array and miss out the local stage?

So normally I would work with globals directly…

if (global.get("manover")===0) global.set("manover",20);

But I can’t seem to do that with this numeric array but I can with a local copy (or maybe as Colin says it isn’t a copy but a reference?

Pete

@scargill I respectfully suggest you ignore Colin's suggestion. It is not considered good practice.

To work with context values you get it, modify it however you need, and then set it back.

Ignore the fact that for Array and Object types then JavaScripts pass-by-reference behaviour may make the final set a redundant step.

But I DO need a global.

I should have said solved using a local copy/reference, now I’m not entirely sure which it is. If you have to copy it back to the global then it’s a copy, if not then it’s a reference.

Ok, my mistake! I first didn't' catch what you meant by local var.

I tried without global.set() and it doesnt' work!

var hum = global.get('hum') || [];

hum.unshift(msg.payload);
hum.splice(24, 1);

//global.set('hum', hum);
msg.payload=hum;
return msg;

Edit: anyway I'd follow @knolleary advice, especially considering the coming version 0.19.

1 Like

First item.. sometimes I initialize a global in my init frow, then use that global var over time without using an intermediate temporary local.

In this case I initialized a global numeric (24 offsets 0-23) array no problem but when I tried moving elements along the line the hard way to add in a latest value to offset zero, I found I could not update values for any but the first 2 offsets.

I would start at the end-1 and copy that to the end, then go to end-2 and copy that to end-1 etc then eventually copy the current humidity into offset 0. Once per hour for 24 hours… or for testing, once per several seconds – except most of the values would not update.

As soon as I worked inatead on a local array it all worked.

I’m with you on the second item, Nick – use SET to update the original global.