Change node - can this be done?

Sorry folks, another Today's dumb question.

Recent events have had me going in circles with the change node.

Base line of the question is this:

Say I am expecting a number value to come in and for what ever reason it is text.

(to clarify)
Say I am expecting 30 and get 30.

My change node has this in it:

Here's the node for perfect clarity:

[
    {
        "id": "44e43511439631d5",
        "type": "change",
        "z": "aad05e94.e66068",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "msg.payload * 1000 * 60",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "delay",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1070,
        "y": 2930,
        "wires": [
            [
                "2409a9f98804fd88",
                "9a949d29ccd6c117"
            ]
        ]
    }
]

So:
set msg.payload to
J: msg.payload * 1000 * 60

Basically making the 30 into 30 minutes. (Yes?)
I did the maths the longer way only for ..... clarity?

Anyway.

So I get a 30 and not a 30 coming in.

I can't do:
J: parseInt(msgmpayload) * 1000 * 60
can I.

I'm suspicious (well, I've tested it and it doesn't work) it can't be done.

But if there is a trick that would allow that it would be handy to know.

Back to what I've just said about the input.

YES

It is sloppy programming.

It was an example that is a good example to ask the question.

NO

I do NOT want to promote such bad practices. But to me the question is there begging.

Doesn't $number(msg.payload) work?

image

1 Like

@Trying_to_learn
Do not use msg.payload in a JSONata expression.
either
$$.payload
or just
payload.
Compatibility mode is deprecated

All the JSONata functions are listed in the JSONata Expression editor, function reference.

1 Like

I apologise to @Trying_to_learn if my example uses deprecated syntax. I knew that both msg.payload and payload work in jsonata, did not know one was better.

Compatibility, pah! what about consistency?

It's a constant irritant in Node-red to have to write {"payload": blah} in one place and {payload: blah} in another, msg.payload in one place, payload in another and {{payload}} (or is it {{msg.payload}} ?) in a third.

What can I say about $$.payload? It's just pain bonkers (or do i mean jsonata?), especially on a Linux machine where $$ is already heavily overloaded.

deep breaths... rant over.

1 Like

This post will give an example why $$.payload should be used.

You are using a application based on Javascript, which has no consistency, what do you expect.

1 Like

Where do you have to write it like that? In JavaScript you can use that shortcut (because there are no special characters in the property name) but it is not compulsory.

It was good to get it out :slight_smile:

Why did nobody warn me? Should have stuck with bash scripts...

1 Like

Wow!

This is a can or worms.

Ok, thanks.

A BETTER example of where I need it is to detect if things are NOT set.

excuse the digression

I seem to love subflows.

As I am evolving, I am learning better (well, ok, that's from my point of view) ways to do things and using nodes more efficiently.

So I have a subflow and it has environment values that are used.
In a recent example it is/was power

It was used in a change node and appended to a string.

J: topic & '/cmnd/power' & $env('power')

Now if power is not set in the subflow's node, I need to get an error thrown or do something to set it to a default.

So my theory is:

J:
power = $env('power')
if (power == undefined)
{
   throw an error
}
topic &  '/cmnd/power' & $env('power')

I know the last line could be optimised.
For now I'll leave it as is so as to not complicate things and keep on target for this stage.

Is/would that work - in theory?
Or even better: really.

... and JSONata
... and Regex
... and Mustache
... and JSON
... and Angular v1
... and now Vuetify

So yeah, lots of different approaches with different syntaxes to handle!

Anyway, back to Andrew's dilemma -- seems you found an edge case where the JSONata expression evaluator does not validate missing env vars as well as JS does. If you want to throw an exception, you should probably use a function node with logic something like this:

let power = env.get("power");
if (!power) {
  node.error("ENV 'power' is not defined!");
  return null;  // stop the flow processing
}
msg.payload = msg.topic + "cmnd/power" + power;
return msg;

JSONata is a bit more restricted in its data types and error handling logic than JS is, because it's designed to be a JSON in => JSON out transformation tool, not a general purpose programming language. Incidentally, that is what makes it flexible enough to be included in node property definitions (i.e. the change node's J: option). Most of us would prefer to use plain Javascript syntax like
msg.topic + 'cmnd/power' + env.get('power')

rather than the unintuitive & operator is JSONata -- but Javascript needs to be interpreted in a sandbox VM, and so it needs its own function node to provide that structure.

So if you just want to ensure a default value is used if your env var is missing, you can do this in JSONata:

(
  $power := $env("power") ? $env("power") : "MISSING";
  topic & "cmnd/power" & $power
)

To add to @shrickus, you can also call an error in the JSONata expression and stop any output, a message will be shown in the debug sidebar, but it is not catchable.
e.g.

$$.topic & "/cmnd/" & ($env("power")  ? $env("power") : $error( "ENV POWER MISSING"))

1 Like