Changing global variable inside the function node

#1

I have global variable

global.set("obed07", {payload: {template: "foo",Total:555, Today:0, Yesterday:0}});

How I can change it inside the function block. I am using following code now.

var obed = global.get("obed07"); 
obed.payload.template="bar";
global.set("obed07",obed);

Is there some other, more direct way (one line of the code) to achieve this?

#2

Not really, that's about as good as it gets. There are ways to reduce that down by a line but it would be hard to follow - really not worth it. JavaScript is actually very good at optimising things like this when it actually runs so I wouldn't worry about it.

#3

Have you tried...

global.get("obed07").payload.template="bar";

Then inspected the context side bar to see if it works?

Obviously the item will need to be present in global context 1st.

#4

That won't work as it doesn't actually update the variable.

#5

I wasn't sure if an object reference was returned & thus updatable directly. Can't get my head around this one. I'm certain I've done something similar?!?

#6

Drat! It does work actually.

However, I'm far from convinced that isn't the intended outcome. Let me read the docs again.

#7

As I thought, the docs are clear about this - you should be using set to update the variable. I think that means that the approach you've given is an unintended outcome and so couldn't be relied upon.

However, we really need "official" input from @knolleary or @dceejay.

#8

yeah I just did a sanity check & I was right :stuck_out_tongue:

I believe it is perhaps not the intention however a side affect of the Javascript language. The global/flow get() functions return the object & thus its a reference (not a copy) & therefore modifiable.

#9

Not only would I not want to rely on that but I also think that it is much harder to follow - coming back to it in 6m time I think it might take a while to work out. Certainly if, for some reason, the documented approach is enforced, it might be difficult to spot an debug.

#10

I am certainly no expert in all things javascript however I can see no way this could be prevented or broken for that matter. When you store an object (where ever that is) you ultimately store a reference & thus retrieve a reference. If it wasn't, you'd be setting/getting a clone/copy & then this would be a whole new problem (deep vs shallow copy).

Note: I'm not advocating this approach (its certainly less readable to those unaware of the subtleties of javascript. the get set functions are far clearer in their intent.

#11

PS, for anyone reading this, i suspect it will ONLY work for objects / arrays - i.e. wont work for strings/numbers or any other immutable.

#12

Depending on the implementation of the storage plugin it will probably break. Most likely with any non-memory based context storage.

#13

oh yes - didnt think of that.

However, it depends how the storage mechanism works. If i were to write it, the store would primarily be memory based (writing to file when property is updated, but only reading only upon node-red startup) in which case it would still work.

But yes, as @TotallyInformation, said, probably best to avoid.

#14

well we don't mind if you wish to bend the rules as long as you are happy knowing the consequences, but probably best not to encourage others to do so if they are unaware of the gotchas.

1 Like
#15

Except the update would not get written to disk and would be lost when Node-RED restarts. Not exactly the idea of a persistent context.

You need to call .set so the context storage plugin know it has something to save.

1 Like
#16

And theres the silver bullet :slight_smile:

Of course you are correct for a file based store. The functions would need to be executed.

@Petr by now hopefully you will see although yes, you can update in one line, should you ever use file back context or the implementation of get/set change, you may have problems. Stick with what you have :slight_smile: unless you fully understand the what and the why

1 Like
#17

Guys, you are great here! Thanks
I didn’t intended to go so deep :smiley:
For me (as a Pythonist, who is trying to taste js soup now) it is difficult to accept 3 lines of the code and all those curly and semicolon things. But I am trying to work hard and to accept this "new different culture" :smiley:

I was thinking about to change the property of the global object directly, without the necessity to:

  • declare variable
  • call the whole object to the script node as a local object
  • changing the property of the local object
  • returning local object back to the global variable.
    BTW, It looks to me, I am rewriting/resetting the whole object stored inside the global variable instead of rewriting property value only.

I was really thinking about some semantic like you see below, and, of course, trying to find some examples, I was not successful (yes, it was a long night lol)

global.set("obed07").payload.template = "bar";
global.set("obed07".payload.template:"bar");
global.set("obed07.payload.template":"bar");

// for the readers of this forum
// this is an example of the BAD syntax, dont use it

Thank you again for explanation.
BTW: how often / in which cases to use global variables? I have a small project managing 10 Sonoff mqtt POW R2 switches and I need to keep the recent state of each switch and compare it with new values from the incoming mqtt flow . Till now, the only way I have found for this is to use globals.

#18

Haha, well that cuts both ways. I learned Python long before I learned JavaScript. In fact it was where I first really understood about object-based programming. Sadly, the Python masters completely missed some important developments in the world and that meant that Python was never integrated as well into the web world. At the same time, Node.JS came along which meant that, as a non-pro programmer, I chose a single language to cover both front- and back-end programming. Bye-bye PHP and Python (and PERL!) - I've only so much time to try and remember how to do things.

I don't like all the {}; stuff either - in fact I refuse to use ; unless they are absolutely necessary (only about 3 use cases in JavaScript that actually need a ;).

Argh! I keep forgetting that this is actually possible!!! That works absolutely fine :smile:

Except that you just got one thing slightly wrong, here is the correct answer (colons are for objects, comma's for function arguments):

global.set("obed07.payload.template","bar")

This also works in case you are wondering:

flow.set("obed07.payload['template']","jim")
#19

Aaaa.... so no more 3 lines of code?
Is it really possible to change the property of the global variable in the one line of code within the function code? No need to define, get, change, set? Just set directly?

What about the second syntax?

flow.set("obed07.payload['template']","jim")

What do the square brackets mean? I don’t understand it.

#20

It's for accessing properties of an object
E.g object.prop and object["prop"] are the same. Means you can dynamically access properties of an object.