From string to array in jsonata

Hello everyone,
Following a previous post on redis contrib node (Make redis config node more "dynamic") I am now struggling on the config node from https://flows.nodered.org/node/node-red-contrib-redis
In order to use a redis cluster, the config node as to be initialised with an array looking like this:

[
   {
      "host": "192.168.1.107",
      "port": 6380
   },
   {
      "host": "192.168.1.6",
      "port": 6379
   },
   {
      "host": "192.168.1.186",
      "port": 6379
   },
   {
      "host": "192.168.1.132",
      "port": 6379
   },
   {
      "host": "192.168.1.22",
      "port": 6379
   },
   {
      "host": "192.168.1.224",
      "port": 6379
   }
]

The node can be configured (for the redis server part) using jsonata.
I like to get this value out of an env variable, which is a string.

Unlike the json node, I cannot figure a way to transform a string "looking like an array" to an actual array using jsonata.
I can format the env variable differently if it helps, however, from with the redis node it must be an array as showed above.
Is there a way to achieve that through jsonata transformation ?

Thanks !

$eval() would be the way to convert a json string to an object, Or if you had a format like

host:port
host:port

you could split it.
e.g.

[{"id":"43d28cb357dde293","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"host\":\"192.168.1.107\",\"port\":6380},{\"host\":\"192.168.1.6\",\"port\":6379},{\"host\":\"192.168.1.186\",\"port\":6379},{\"host\":\"192.168.1.132\",\"port\":6379},{\"host\":\"192.168.1.22\",\"port\":6379},{\"host\":\"192.168.1.224\",\"port\":6379}]","payloadType":"str","x":130,"y":2600,"wires":[["4d4ff611d3d2c527"]]},{"id":"4d4ff611d3d2c527","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$eval($$.payload)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":2600,"wires":[["387675af5fa81414"]]},{"id":"387675af5fa81414","type":"debug","z":"b779de97.b1b46","name":"debug 299","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":450,"y":2600,"wires":[]},{"id":"de42835e6ad8b66b","type":"change","z":"b779de97.b1b46","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$split($$.payload, \"\\n\").($parts:=$split($,\":\");\t{\"host\": $parts[0],\"post\":$parts[1]})","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":2660,"wires":[["387675af5fa81414"]]},{"id":"3619501058a5b350","type":"template","z":"b779de97.b1b46","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"192.168.1.107:6380\n192.168.1.6:6379","output":"str","x":300,"y":2660,"wires":[["de42835e6ad8b66b"]]},{"id":"5043d3d9928e476d","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":2660,"wires":[["3619501058a5b350"]]}]

Obviously $$.payload would be $env("env_property_name")

If the string is valid json, the JSON node is the right thing to use.

I think @greengolfer is trying to set an array in the config field of the redis node (which allows jsonata), so can not use a json node.

Exactly... The redis config can't use incoming message. So, jsonata is the only way, I think.

What @E1cid suggested works (thanks a lot) though, it doesn't work with this contrib flow...

I have an env variable called cluster (!) with:
[ { "host": "192.168.1.107", "port": 6380 }, { "host": "192.168.1.6", "port": 6379 }, { "host": "192.168.1.186", "port": 6379 }, { "host": "192.168.1.132", "port": 6379 }, { "host": "192.168.1.22", "port": 6379 }, { "host": "192.168.1.224", "port": 6379 } ]

If I do as suggested $eval($$.$env("cluster")) in a inject node to test, it is fine the output is the expected array.

If I do the same think in the redis config node, it doesn't.
Looking at the flows.json, the config node looks like:

   {                                            
        "id": "c8318783347b07af",                
        "type": "redis-config",                  
        "name": "Cluster",                       
        "options": "$eval($$.$env(\"cluster\"))",
        "cluster": true,                         
        "optionsType": "jsonata"                 
    }, 

Which seems to be correct.
However, the node complains that the syntax is not correct.

Looking at the redis.js code, it looks like this:

  function RedisConfig(n) {
    RED.nodes.createNode(this, n);
    this.name = n.name;
    if (this.optionsType === "") {
      this.options = n.options;
    } else {
      this.options = RED.util.evaluateNodeProperty(
        n.options,
        n.optionsType,
        this
      );
    }

Not being fluent in javascript, I am stuck :frowning:

I have raised an issue on the other matter (clustering as env variable). No answer after a month. It looks that this redis contrib node has lost his parent(s). :cry:

Seems is the key word here as the $$ is not correct

$eval($env("cluster"))

As suggested here

Thanks. You are right.

For my defence :wink: in the inject node $eval($$.$env("cluster")) and $eval($env("cluster")) are giving the same thing on the debug.
Not as part of the redis config node. The latter works. Not the former. Mmmm...
One day I'll understand jsonata. Maybe.

Just for info : -
$$ means you are in base context, i.e msg
Now the . would mean one of two things.
1, path property expected
2, map over the array $$
As there is no array and no path property present, just a function, an error is thrown.
So $$ should only be used if you are referencing the msg context.

1 Like

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