JSONata and arrays in root of msg

Can anyone help me with why this JSONata, $$[$number($now('[h#1]'))].Price/10, won't give me the electricity price when I have this array in the payload with prices per hour in a day. The test of it works but all I get is the whole first array object. I just realised I should specify payload somewhere in the start of the JSONata but I'm unable to get a change in behaviour:

[
{"Area":"Oslo","Timestamp":"2019-11-14 00:00","Price":408.01,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 01:00","Price":404.87,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 02:00","Price":401.42,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 03:00","Price":402.53,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 04:00","Price":407.81,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 05:00","Price":416.33,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 06:00","Price":440.89,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 07:00","Price":504.81,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 08:00","Price":513.84,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 09:00","Price":498.22,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 10:00","Price":479.34,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 11:00","Price":486.55,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 12:00","Price":493.55,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 13:00","Price":497.2,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 14:00","Price":527.44,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 15:00","Price":531.6,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 16:00","Price":551.49,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 17:00","Price":600.6,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 18:00","Price":489.49,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 19:00","Price":457.22,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 20:00","Price":433.58,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 21:00","Price":426.68,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 22:00","Price":416.64,"Valuta":"NOK/MWh"},
{"Area":"Oslo","Timestamp":"2019-11-14 23:00","Price":412.68,"Valuta":"NOK/MWh"}
]

You are right that you need to specify payload in there somewhere. Try:

$.payload[$number($now('[h#1]'))].Price/10

That looks more sensible but then I must be messing up something else because all I get from the debug node is the first object?

What exactly does your message look like? We've assumed that the array you've shared is in msg.payload. But I do note the debug message about the one you highlight suggests possibly otherwise.. but without knowing what the debug node is showing its hard to say.

Here you can see the expression working: http://try.jsonata.org/ByXMkhqsS - with the array you've shared set under msg.payload.

Sorry for my confusion here. The node-red-contrib-nordpool-api node, as you rightly noticed, indeed returns the array of price objects at the root of msg as shown in the first post (not in payload, I've edited the topic of this thread to reflect that now). I guess that is why my original JSONata test worked on the copied object from the debug tab. I got confused when trying to work with a payload from there on.

Does the trouble then stem from me trying to set the payload property on the msg array ? How can I move the array to an intermediary/temporary property on the msg when it's a root array, in order to both work with the original data and set a new payload property?

This is embarrasing and may be caused by my fever these days, but as @knolleary helped me understand and get the jsonata part right, does anyone have a solution for elegantly working with a root array and setting a new payload at the same time?

I can’t get you a proper example but take a look at the construction presented here. First part of the page, please don’t bother to try tge bottom example, the sentence leading to it is 100% correct. https://docs.jsonata.org/programming
My attempt would be to put this in a change node set to msg.payload, with a JSONata content. Then to deconstruct the array. The deconstruction can happen in variable/functional writing like in the link above. Next create the payload as you like it to look, and have that be the last part of your expression. Use the try.jsonata.org page, it’s worth gold for advanced jsonata expressions.

I’ve done similar things like your issue before, and while JSONata works it may feel like too difficult soon once you touch these aspects of functionality. If I remember I’ll work it out a bit more in the morning.

I'm not sure I understand what you mean by 'a root array'

A message is an Object with properties. If it has an array of values it must be under a property of the message. A message cannot just be an array.

If there's a node sending a message like that, then that is completely wrong and the node must be fixed.

I wonder if you are using a function node to build the "root array".

If you return an array of objects (like the one you shared in the OP) in a function node then the function node will understand that you are using multiple outputs and will send one object for each output. You will get only the first object if there is no second output configured in the function node.

Perhaps a flow can explain better. Try this code inside a function node with only one output and then add a second output and trigger the flow again. Edit: add a debug node to each output of the function node to visualize how it works.

let newmsg = [{"a" : 1}, {"b" :2}];
return newmsg;

I am actually not building the "root array" (@knolleary whereby I mean that the array is not under a property) myself, it is output from the contrib node I mentioned (which probably shouldn't do that).

So, I didn't manage to manipulate that msg while also working with the data, and regret that I didn't manage to be elegant with JSONata, but I fixed it by sending an entirely new message in a function node instead:

var msg1 = {};
var d = new Date();
var t = d.getHours();
msg1 = {
    topic:msg[t].Area + " " + msg[t].Valuta + "/10", 
    payload:msg[t].Price/10, 
    timestamp:msg[t].Timestamp,
    }
node.send(msg1);
return;

Oh, and thanks for the link, @afelix, I have a steep learning curve ahead of me.

Based on your code in the function node, the exact thing Nick described is happening. The message is not an object but an array. If the node was okay, your code should at least have had to interact with msg.payload[t] rather than with msg directly. Seeing that it is not, this suggest a huge design mistake in the node you are using.

However, the Nordpool node should return a msg.payload that is an array according to this line so I’ve no clue at all what is happening here

Yes, I know that by now. It’s what I was trying to work around in the latter replies. But it’s not the nordpool node (which hasn’t been updated for two years and is not available in the palette anymore) but the nordpool-api node.

But, as was suggested, have you tried contacting the node author to get it fixed? as it is currently not behaving, and should not output an array on the root.

Definitely, as the example on the node page shows exactly that. There’s no link to a repository published, nor a way to report issues.


But just looking at the installation instructions makes me want to file another issue here.

I installed the node just to look at the code, appears to be an error but the way it is documented suggests otherwise. Here's the last part which is relevant to what is happening:

Promise.all([promise, promise1]).then(function() {
    var sortpris = priser.sort((a, b) => a.SortTime - b.SortTime)
    for( var i = 0; i < priser.length; i++){
        delete priser[i].SortTime
    }
    msg.payload = [priser]
    node.send([msg.payload])
    node.status({ fill: 'green', shape: 'dot', text: 'Ready' });  
});   

Code is a mixture of ES5 and ES6, and includes both var as well as let/const spread all over. Maintainability with regards to scope might be difficult too, but with the code not publicly released contributing will be hard. According to the package.json it is released as ISC though.

The only way I can find to contact the developer is through a Norwegian home automation forum where the creation of these nodes were first announced.

I tracked down the author and he was happy to update the node. But was concerned about the breaking change though as the last part in the following should of course have been node.send([msg])

node.send(msg). surely ?
The payload is the array.
Yes it will break but it is broken already. so the version should be bumped appropriately.

1 Like

Nordpool-API has now been updated and I have now come full circle and can be elegant as I wanted with the original JSONata, and @knolleary 's payload addition :slight_smile:

2 Likes

Please beware of a likely bug in this node (3.0.0). When the price is above 1000, the payload becomes 1. This is perhaps only a problem when using any of the nordic currencies due to exchange rates and price levels, but still. I've tried to find a way to get in touch with the author but wasn't able. Any ideas?