Saturday, January 20, 2018

Manipulating JSON - Example 1

This was a request for help posted in Node-RED group.


Requirement:

To write a function that from message below return  different messages with the keys as topics (Time,Uptime, etc..) and as payload the value of each key.


Message provided:



Desired outcome:





















Proposed solution:

A code inside a function node that will iterate over all the keys in the original payload and will create an array (named output) that will contain objects with properties that complies with the requirement: {topic:key, payload:value}. As a reminder note that when a function node has only one output and the returned object is an array then several messages will be sent over the output (one for each element of the array).



// Declare an array to hold the objects
var output = []; 

var x;
// var x will hold each key from the msg.payload
for (x in msg.payload) 

// Store in the array output the objects, except for key = Wifi
{
    if (x != "Wifi") 
    {
    output.push({topic:x, payload:msg.payload[x]}); 
    }
}


// Store in the array output the objects  for key = Wifi
for (x in msg.payload.Wifi)
{
    output.push({topic:x, payload:msg.payload.Wifi[x]}); 
}
    
// below return statement will return a message for each element of the array
return [output];



Flow:


Notice that for the purpose of testing the logic I stored in the inject node the testing object as a JSON  structure. The inject node returns this JSON structure as a Javascript object (inside msg.payload), therefore no need to use the JSON node to convert.


{
    "Time": "2017-12-26T22:39:08",
    "Uptime": 4,
    "Vcc": 3.25,
    "POWER": "ON",
    "Wifi": {
        "AP": 1,
        "SSId": "JAZZTEL_david",
        "RSSI": 72,
        "APMac": "20:89:86:1E:31:E2"
    }
}



Remarks:

This user case shows that transforming JSON structure is a common need. An alternative approach would be using JSONata expression (along with a Change node) but we respected the specific requirement to build this flow using a function node.

It would be interesting to generalize this flow to perform the same operation regardless of the amount of keys like "Wifi" in the original message.



Flow to import into Node-RED:


[{"id":"f2a5e861.443a28","type":"debug","z":"97920a03.8f8d28","name":"","active":true,"console":"false","complete":"true","x":470,"y":120,"wires":[]},{"id":"cbb69cda.02a22","type":"inject","z":"97920a03.8f8d28","name":"","topic":"","payload":"{\"Time\":\"2017-12-26T22:39:08\",\"Uptime\":4,\"Vcc\":3.25,\"POWER\":\"ON\",\"Wifi\":{\"AP\":1,\"SSId\":\"JAZZTEL_david\",\"RSSI\":72,\"APMac\":\"20:89:86:1E:31:E2\"}}","payloadType":"json","repeat":"","crontab":"","once":false,"x":170,"y":120,"wires":[["8a4b3666.734578"]]},{"id":"8a4b3666.734578","type":"function","z":"97920a03.8f8d28","name":"Parse payload","func":"var x;\n// Declare an array to hold the objects\nvar output = []; \n\n// var x will hold each key from the msg.payload\nfor (x in msg.payload) \n\n// Store in the array output the objects, except for key = Wifi\n{\n    if (x != \"Wifi\") \n    {\n    output.push({topic:x, payload:msg.payload[x]}); \n    }\n}\n\n\n// Store in the array output the objects  for key = Wifi\nfor (x in msg.payload.Wifi)\n{\n    output.push({topic:x, payload:msg.payload.Wifi[x]}); \n}\n    \n// below retunr statement will return a message for each element of the array\nreturn [output];","outputs":1,"noerr":0,"x":320,"y":120,"wires":[["f2a5e861.443a28"]]}]

No comments: