Dealing with payloads with different structures

Hi all,

The first week in using Node-RED and love it! quick question.

I am using a building monitoring device that outputs a different object structure once a day to send up its battery readings however when that happens it uses the same path that I parse for my temperature readings in its normal reporting state

What I mean by that is 23 hours a day it sends payload[0].readingList[0].value as temperature
but then on the 24th hour it sends up payload[0].readingList[0].value as battery level

example of each payload structure:

When Object0 is parsed with battery it throws out my temp readings for that one payload. I would also like to capture the battery level and output that to another node every time it gets sent

By using object paths to parse my payload clearly isn't the best practice with structures that can change so what would be the right way other than using basic paths to capture my values. Ideally I would like to reference the "channelId" in this case battery gets sent as "channelId : 1" and temp gets sent as "channelId : 3"

Thanks in advance !!

Put a switch node in before your processing code - get it to switch on the Value of ChannelID i.e. either 3 or 1

You can get the full path to the channel ID in the Debug window by hovering over the field in question and then choosing the _ to copy the path

it will probably be

msg.payload.readingList.ChannelID

Craig

Depending on what you want to do with the data, you can filter the array and only output the values you are looking for or use a switch node like @craigcurtin suggested that will pass the message if it matches.

The array may be in a different order when it arrives, getting the first or second element is not the proper way to do this.

With a function node you can filter them (either based on label or channelId):

const input = msg.payload.readingList
const needle = ["battery", "temperature"]
const result = input.filter(i => needle.some(value => i.label.includes(value)))

msg.payload = result

return msg;

Or:

const input = msg.payload.readingList
const needle = [1,3]
const result = input.filter(i => needle.some(value => i.channelId.toFixed().includes(value)))

msg.payload = result

return msg;

This will only return the filtered elements from the array.

example flow

[{"id":"289cc6bd20821bcf","type":"inject","z":"6c52c1f71d120b99","name":"with battery","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"readingList\":[{\"channelId\":3,\"type\":\"temperature\",\"value\":21.7,\"label\":\"temperature\"},{\"channelId\":1,\"type\":\"percentage\",\"value\":25,\"label\":\"battery\"},{\"channelId\":5,\"type\":\"blabla\",\"value\":21.7,\"label\":\"something else\"}]}","payloadType":"json","x":238,"y":384,"wires":[["ff1f04cb9d619db9","caafbdd9eedf738e"]]},{"id":"ff1f04cb9d619db9","type":"function","z":"6c52c1f71d120b99","name":"based on label","func":"const input = msg.payload.readingList\nconst needle = [\"battery\", \"temperature\"]\nconst result = input.filter(i => needle.some(value => i.label.includes(value)))\n\nmsg.payload = result\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":464,"y":384,"wires":[["e194110390ce0dd5"]]},{"id":"fe98b4d4d175176c","type":"inject","z":"6c52c1f71d120b99","name":"without battery","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"readingList\":[{\"channelId\":3,\"type\":\"temperature\",\"value\":21.7,\"label\":\"temperature\"}]}","payloadType":"json","x":224,"y":432,"wires":[["ff1f04cb9d619db9","caafbdd9eedf738e"]]},{"id":"e194110390ce0dd5","type":"debug","z":"6c52c1f71d120b99","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":684,"y":408,"wires":[]},{"id":"caafbdd9eedf738e","type":"function","z":"6c52c1f71d120b99","name":"based on channelId","func":"const input = msg.payload.readingList\nconst needle = [1,3]\nconst result = input.filter(i => needle.some(value => i.channelId.toFixed().includes(value)))\n\nmsg.payload = result\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":474,"y":432,"wires":[["e194110390ce0dd5"]]}]
1 Like

You can us javascript find(), Or JSONata Predicate query
e.g.

[{"id":"289cc6bd20821bcf","type":"inject","z":"30af2d3e.d94ea2","name":"temp at 1","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"readingList\":[{\"channelId\":1,\"type\":\"percentage\",\"value\":25,\"label\":\"battery\"},{\"channelId\":3,\"type\":\"temperature\",\"value\":21.7,\"label\":\"temperature\"},{\"channelId\":5,\"type\":\"blabla\",\"value\":21.7,\"label\":\"something else\"}]}","payloadType":"json","x":170,"y":300,"wires":[["bd6367d1.994708","8478f57c.09301"]]},{"id":"bd6367d1.994708","type":"change","z":"30af2d3e.d94ea2","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$$.payload.readingList[label = \"temperature\"].value ","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":320,"wires":[["e194110390ce0dd5"]]},{"id":"8478f57c.09301","type":"function","z":"30af2d3e.d94ea2","name":"","func":"msg.payload = msg.payload.readingList.find(obj => obj.label === \"temperature\").value\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":380,"wires":[["e194110390ce0dd5"]]},{"id":"fe98b4d4d175176c","type":"inject","z":"30af2d3e.d94ea2","name":"temp at 0","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"readingList\":[{\"channelId\":3,\"type\":\"temperature\",\"value\":21.7,\"label\":\"temperature\"}]}","payloadType":"json","x":130,"y":360,"wires":[["bd6367d1.994708","8478f57c.09301"]]},{"id":"e194110390ce0dd5","type":"debug","z":"30af2d3e.d94ea2","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":626,"y":324,"wires":[]}]
msg.payload = msg.payload.readingList.find(obj => obj.label === "temperature").value
return msg;
$$.payload.readingList[label = "temperature"].value 
2 Likes

Brilliant thank you guys, I really appreciate your prompt help!

I tried all three options to learn as much as I can. Ultimately went with @bakman2 in the flow and it works great !!!!