What is the correct way to use jsonata inside a switch node with "has key" rule?

Hi

I have the following situation, I want to test if a given msg.payload has some keys. Let's say for example:

msg.payload.keyOne
msg.payload.keyTwo

I know i can check that with a function node, but I'm curious about achieving that with jsonata. Using the following expression:


has key: "keyOne"

actually works. But:

has key: "keyOne" and "keyTwo"

does not.

nor $.(keyOne and keyTwo) as jsonata expression

I tried several approaches but I'm not sure how can i achieve that. Apart from creating a function node and creating the logic inside it.

This seems to work:

1 Like

thank you very much, I tried several ways but it seems I didn't try that one. Since i was already selecting msg.payload in the property i though that was not necessary in the expression.

I was astonished my attempt worked too! Definitely can't explain it, I don't speak Jsonata.

Note that it does not work with
payload: {"keyOne": false, "keyTwo:" 42}

The reason is that the test is not testing the presence but whether they are truthy. So each one is cast to be a boolean and then the AND performed

I would think, if payload has only the two keys

["keyOne","keyTwo"] = [$keys($$.payload)]

in property input and is true as rule

e.g.

[{"id":"2cabca371eb27b4e","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"keyOne\":false,\"keyTwo\":42}","payloadType":"json","x":90,"y":2200,"wires":[["2461013912501444"]]},{"id":"2461013912501444","type":"switch","z":"d1395164b4eec73e","name":"","property":"[\"keyOne\",\"keyTwo\"] = [$keys($$.payload)]","propertyType":"jsonata","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":230,"y":2200,"wires":[["51e23011bba3999b"]]},{"id":"fdf90a4bf8ad5b04","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"keyOne\":false,\"keyThree\":42}","payloadType":"json","x":90,"y":2240,"wires":[["2461013912501444"]]},{"id":"51e23011bba3999b","type":"debug","z":"d1395164b4eec73e","name":"debug 2460","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":410,"y":2200,"wires":[]}]

Or if multiple properties of payload

$count($keys($$.payload)[$ in ["keyOne","keyTwo"]])

and rule == 2
e.g.

[{"id":"2cabca371eb27b4e","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"keyOne\":false,\"keyTwo\":42, \"test\":33}","payloadType":"json","x":90,"y":2200,"wires":[["a6629ce22e09cfe9"]]},{"id":"a6629ce22e09cfe9","type":"switch","z":"d1395164b4eec73e","name":"","property":"$count($keys($$.payload)[$ in [\"keyOne\",\"keyTwo\"]])","propertyType":"jsonata","rules":[{"t":"eq","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":250,"y":2200,"wires":[["51e23011bba3999b"]]},{"id":"5133659df03aee6e","type":"inject","z":"d1395164b4eec73e","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"keyOne\":false,\"keyThree\":42}","payloadType":"json","x":90,"y":2240,"wires":[["a6629ce22e09cfe9"]]},{"id":"51e23011bba3999b","type":"debug","z":"d1395164b4eec73e","name":"debug 2460","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":410,"y":2200,"wires":[]}]
1 Like

But in the property negates the possibility of using other rules in the switch statement (my case). But actually your solution works well as a rule anyway as jsonata expression. So thanks for your help.

One of the reasons for looking into jsonata is that i tend to use switch cases and usually i send an int code to a switch statement trough a fuction node, but having jsonata can reduce the amounts of nodes in certain scenarios.

You never said you wanted to use other rules.
But just move the whole thing to a rule
e.g.

$count(["keyOne","keyTwo"][$ in $keys($$.payload)])  = 2

Or

["keyOne","keyTwo"] = [$keys($$.payload)] 

[edit] reversed the expression as would use less processing if payload had more properties.

1 Like

Yes that's true I didn't mention it. I was just pointing that out trying to find the most versatile solution, not necessarily for my specific case, so sorry for any misunderstanding. Yes i mentioned in my comment as well that could work as rule as well.

I still prefer the boolean expression solution, but not sure how to implement that solution without the caveat of the possible "false". But your solution of counting can be the best approach in most situations. thanks.

It would also fail if the value were zero.

2 Likes

Jbudd's solution would also fail if keyOne or keyTwo were an empty object or array. So not really a solution.

[edit]
Here is a boolean solution to.

$not(false in ["keyOne","keyTwo"].($ in $keys($$.payload)))
2 Likes

Well I dunno about you lot but i'd do it with two switch nodes in series.
One testing for keyOne and the other for keyTwo :grinning:

And if it's just a simplified example, you really want to test for many keys, I'd put all the switch nodes on another flow with link-in and link-return.

I'm glad I mentioned my version was faulty before everyone else did!

3 Likes

thanks for your response, and all other people for helping out.

Actually i was testing something similar before your message.

(("keyOne" in $keys($$.payload)) and ("keyTwo" in $keys($$.payload)))

but your solution seems more elegant.

I never tried jsonata before so it was good to test things out.

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