JSONata: Using the result of an Object Function to reference a Message Property in a Change Node

Hello all,

I'm new to Node-RED and have been struggling with using JSONata to set nested object properties with the Change Node.

I have the following scenario where I need to access a particular property's value in a nested object, but where I don't know the name one of the parent properties.

I can get the property name using $keys(object) however I then need to use the output of this as part of the dot notation to access the required property. A possible added complication is a hyphen in the unknown property name.

Despite some extensive research I just can't work out the correct syntax to achieve this.

Example object (where the property name "device-0001" is unknown in advance):

{
    "device-0001": {
        "name1": "value 1",
        "name2": "value 2"
    }
}

I can get the unknown property name with $keys(object)

$keys($.payload)[0]

which returns "device-0001"

However, if I use this as part of the dot notation

$.payload.$keys($.payload)[0].name1

then I get undefined returned.

Although I do have two work arounds

  1. Save the object to the flow context first
$flowContext("devices." & $keys($flowContext("devices"))[0] & ".name1")
  1. Use a function node and JS
msg.payload = msg.payload[Object.keys(msg.payload)[0]].name1;
return msg;

I don't want to have to change several existing change nodes to functions nodes if possible and would prefer not to use the flow context. I also feel it should just be matter of using the correct syntax.

Any advice would be appreciated.

Regards

Simon

(Node-RED: v3.0.2)
(Node.js: v18.2.1)

Welcome.

Is the input a single object or an array of objects ? Are you interested in the 'unknown device' ? or do you only want the name1 property ?

In jsonata you can use payload.*.name1

It will easier to get help if you can provide the input payload and the expected output.

1 Like

Does this work?

[
    {
        "id": "b1e189a05183e321",
        "type": "change",
        "z": "7aef6aee2ebec20b",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "key",
                "pt": "msg",
                "to": "$keys($.payload)[0]",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload[msg.key].name1",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 520,
        "y": 120,
        "wires": [
            [
                "5fa6a2c8cdd5e7c7"
            ]
        ]
    }
]
1 Like

Both @jbudd and @bakman2 answers will work. It really depends if the object is as you have shown.
Another alternative is to use the $lookup function.
e.g

$lookup($$.payload, $keys($$.payload)[0]).name1
2 Likes

Hi,

Thank you @bakman2, it is just a single object in this case although I can imagine scenarios where it may be an array of objects in the future. In this instance I'm also not interested in the device property name so payload.*.name1 will work great. I must have missed that you could use wildcards in JSONata, so useful to know about that, thank you

Thank you @jbudd, using two rules works great, slightly disappointed with myself for not thinking of that one!

Thank you @E1cid using $lookup($$.payload, $keys($$.payload)[0]).name1 works great. It is also good to learn about another function, so thank you.

I only didn't include the actual object and required output as it is such a large object with a lot of properties and would have made the original post long.

Thank you all for your assistance, really appreciated.

Simon

I must have missed that you could use wildcards in JSONata

It is one of the core features to use it.

You could make it even easier by just using **.name1, it will traverse through the all its descendants (but could potentially create problems if the same property name is used on multiple levels)

jsonata is extremely powerful, but can be extremely confusing at the same time :')

1 Like

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