If/else in JSONata expressions

Hello. Noob question, but... )
it's posible to use if/else in JSONata expressions?

I have this expression.

{
   "brightness_pct" : payload.brightness,
   "hs_color" : [payload.hue, payload.saturation]

}

In rare case in msg not exist payload.hue and/or payload.saturation. And in this case I need to use just

{
    "brightness_pct" : payload.brightness
}

I try to find examples, but unsuccessful
Thanks

Welcome to the forum @iStitch07,

Good question. You probably know that there is the ternary conditional operator in jsonata. However the trick part of the question is:

In rare case in msg not exist payload.hue and/or payload.saturation

The bottom line is that jsonata can only operate on a valid JSON string.

If payload.hue does not exist and payload,saturation equals, lets say 5, what hs_color will looks like ?

[ , 5] or [null , 5] or [undefined,5] ?

1 Like

this works for me:

{
   "brightness_pct" : payload.brightness,
   "hs_color" : payload.hue and payload.saturation ? [payload.hue, payload.saturation] 
}

Update:

{
   "brightness_pct" : payload.brightness,
   "hs_color" : payload.hue != null and payload.saturation != null ? [payload.hue, payload.saturation] 
}

This is actually better as it will work if hue or saturation = 0

1 Like

If at least one or both values don’t exist, I need to skip full line, include “hs_color” too

Looks great, I will try this, because I need to complete skip this line if one or both values not exist


{
   "brightness_pct" : payload.brightness,
   payload.hue != null and payload.saturation != null ? "hs_color":  [payload.hue, payload.saturation] 
}

Update:
But coma in first line will be cause of error if I skip the second line

Update2: my variant got a syntax error. Your variant pass the syntax validation, but will cause error with empty “hs_color” service calling :frowning:

@iStitch07 is this a purely academic question?

If not and you really need to solve this then why not just defer to a function node. The logic you require is quite simple to achieve in standard js.

No, it’s not academic question. I try to optimize this flow

If I will add additional function node, I will need to add and another service calling node. And it’s not “pretty” :slight_smile:

Um, no? Confused!

Whatever you want to do in jasonata you can do +more in a function node.

Just return the msg with correct properties/values surely? Not sure why you would need to add 2 outputs and 2 blue nodes (whatever they are)?

I’m not sure and will try

If it possible to create valid json in function node and pass it in payload to data field in service call node - its will be answer

You don't create JSON really (JSON is a string representation of a JavaScript object)

You build a property in the msg (usually payload) then send it onwards.

E.g.

let x;
if(msg.something) { 
 x = msg.thisval
} else {
  x = msg.thatval
}
msg.payload = {
  brightness : x
}
return msg;

In fact, you can probably just set a new property in the msg then set that data property to the same msg.prop you invent

E.g.

if(msg.something) { 
 msg.brightness = msg.thisval
} else {
  msg.brightness = msg.thatval
}
return msg;

Then change the data option to msg and enter brightness

But we return to begin.
I already do something like this in function node


var brg_name = msg.topic + '.brightness';
var sat_name = msg.topic + '.saturation';
var hue_name = msg.topic + '.hue'

var new_val = {};

if(msg.payload.Brightness >= 0) {
    new_val.brightness = msg.payload.Brightness;
    flow.set(brg_name, msg.payload.Brightness);
    new_val.saturation = flow.get(sat_name);
    new_val.hue = flow.get(hue_name);
}

if(msg.payload.Hue >= 0) {
    new_val.brightness = flow.get(brg_name);
    new_val.saturation = flow.get(sat_name);
    new_val.hue = msg.payload.Hue;
    flow.set(hue_name, msg.payload.Hue);
}

if(msg.payload.Saturation >= 0) {
    new_val.brightness = flow.get(brg_name);
    new_val.saturation = msg.payload.Saturation;
    flow.set(sat_name, msg.payload.Saturation);
    new_val.hue = flow.get(hue_name);  
}

msg.payload = new_val;
return msg;

But in service call node I need to set param for service calling

If I have only brightness in payload, then I need to call service

{
   "brightness_pct" : payload.brightness
}

Else, if I have payload.hue AND payload.saturation, I need to call service with this param

{
   "brightness_pct" : payload.brightness,
   "hs_color" : [payload.hue, payload.saturation]

}

Yeah so do that in a function node.

I really don't understand why you don't just do exactly what you're saying

In the function node, just do the logic & update a property in msg (any property you desire) with either
{ "brightness_pct" : msg.payload.brightness }
or
{ "brightness_pct" : payload.brightness, "hs_color" : [msg.payload.hue, msg.payload.saturation] }

Then set the data option in the blue node to msg type and the matching property name

The blue node will recieve the data you send. No need for jsonata.

An I missing something?

What node is that blue node?

the one i looked at doesnt permit JSONata in the Data field but it does permit you to send data in msg.payload.data

If the incoming message has a payload property with domain , service set it will override any config values if set.
If the incoming message has a payload.data that is an object or parseable into an object these properties will be merged with any config values set.

So if that is the same for your node then something like this might work...


//first add a data property and set brightness_pct to msg.payload.brightness
msg.payload.data = {
   "brightness_pct" : msg.payload.brightness;
}

//next, if msg.payload.hue && payload.saturation are present, add hs_color property
if(msg.payload.hue && payload.saturation) {
 msg.payload.data.hs_color = [msg.payload.hue, msg.payload.saturation]; 
}

return msg;

I was try change function node with adding this block

if(new_val.brightness && (!new_val.hue || !new_val.saturation) ) {
    new_val.params = '{ "brightness_pct" : ' + new_val.brightness + ' }';
} else {
    new_val.params = '{ "brightness_pct" : ' + new_val.brightness + ', "hs_color" : [' + new_val.hue + ', ' + new_val.saturation + ']  }';
}

After add to blue node in data field - {{payload.params}}
And got a error

Call-service API error.  Error Message: extra keys not allowed @ data['0']

But in debug all look fine

{"brightness":100,"saturation":100,"hue":234,"params":"{ \"brightness_pct\" : 100, \"hs_color\" : [234, 100]  }"}

Sorry, I’m little slow because working on iPad now :slight_smile:
Blue node its home assistant call service node. I will try do use payload.data

which one?

node-red-contrib-home-assistant-websocket

Why are you doing JSON strings?

Did you try the function I wrote out for you?

The help says...
image

So try the function I stated & pass an object (not JSON)

EDIT, to allow hue 0 and saturation 0 values...

//first add a data property and set brightness_pct to msg.payload.brightness
msg.payload.data = {
   "brightness_pct" : msg.payload.brightness;
}

//next, if msg.payload.hue && payload.saturation are present, add hs_color property
if(msg.payload.hasOwnProperty("hue") && payload.hasOwnProperty("saturation")) {
 msg.payload.data.hs_color = [msg.payload.hue, msg.payload.saturation]; 
}

return msg;

And just leave the Data field blank.

Easy, easy - its my first week with node-red :slight_smile: I still learning :slight_smile:

I will try your code from last post