Almost always our flows will modify the msg object that is passed along the nodes. Node-RED has the powerful change node that help us to fit the msg to our needs. However , it is likely that a more complex msg object will require using a function node for that purpose. I show below a use case posted in the Node-RED forum.
Simply stated, convert below object:
[{"Name":"name1","Number":1},{"Name":"name2","Number":2},{"Name":"name3","Number":3}]
to the new object:
[{"name1":1},{"name2":2},{"name3":3}]
First thing to do is to understand the nature of the objects. Note that our initial object is an array of objects. Each element of the array is an object by itself.
{"Name":"name1","Number":1}
{"Name":"name2","Number":2}
{"Name":"name3","Number":3}
There are many possible ways to write a code tho accomplish such transformation. As you can imagine they will require some iteration (looping).
I describe here four different solutions. All of them using this basic flow: inject node + function node + debug node
First solution: Using the map method
The map method will create a new array by taking each and every element of the original array and processing them with a function code.
This is the JavaScript code inside the function node:
let arr= msg.payload.map(elem => ({[ elem.Name ] :elem.Number}));
msg.payload = arr;
return msg;
The map method will visit each element of the array and will return a modified object, so in the first iteration:
elem = {"Name":"name1","Number":1}
generates: {"name1":1}
Note that the function in the map method (by the way an arrow function) returns an object in the literal notation {"name1":1} thanks to the use of the square brackets surrounding [elem.Name]. Whenever there is a pair of square brackets like this the variable inside brackets is computed. In this example it simply returns the value of the variable elem.Name which happens to be "name1"
You can learn more on computed properties by clicking in this link.
This is how the debug node displays the result f the flow:
and here is the flow in case you want to import and test:
[{"id":"76c98300.8f224c","type":"debug","z":"d61a402.f83d6c","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":496,"y":191.0000057220459,"wires":[]},{"id":"af7dbb81.8640a8","type":"function","z":"d61a402.f83d6c","name":"map method","func":"let arr= msg.payload.map(elem => ({[elem.Name] :elem.Number}));\nmsg.payload = arr;\nreturn msg;\n","outputs":1,"noerr":0,"x":334.9999828338623,"y":190,"wires":[["76c98300.8f224c"]]},{"id":"c50940a3.ee025","type":"inject","z":"d61a402.f83d6c","name":"","topic":"","payload":"[{\"Name\":\"name1\",\"Number\":1},{\"Name\":\"name2\",\"Number\":2},{\"Name\":\"name3\",\"Number\":3}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":162.9999828338623,"y":190.00000190734863,"wires":[["af7dbb81.8640a8"]]}]
Second solution: using the for of loop
The for loop is my preferred method to iterate arrays.
This would be the code inside the function node:
let arr = [];
for (let elem of msg.payload) {
arr.push({[ elem.Name ] :elem.Number});
}
msg.payload = arr;
return msg;
The for of loop visits each element of the array, modifies it and push the newly created object to the temporary array named arr. Later this temporary array will be copied to msg.payload.
The exported flow:
[{"id":"e60806b0.8821c8","type":"debug","z":"d61a402.f83d6c","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":540.0000076293945,"y":147,"wires":[]},{"id":"fb75ae0.2e3655","type":"function","z":"d61a402.f83d6c","name":"For of loop","func":"let arr = [];\n\nfor (let elem of msg.payload) {\n arr.push({[elem.Name] :elem.Number});\n}\n\nmsg.payload = arr;\n\nreturn msg;","outputs":1,"noerr":0,"x":395,"y":146.99999809265137,"wires":[["e60806b0.8821c8"]]},{"id":"18252e58.62eae2","type":"inject","z":"d61a402.f83d6c","name":"","topic":"","payload":"[{\"Name\":\"name1\",\"Number\":1},{\"Name\":\"name2\",\"Number\":2},{\"Name\":\"name3\",\"Number\":3}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":223,"y":147,"wires":[["fb75ae0.2e3655"]]}]
Third solution: for loop + object destructuring
Same as the previous one with a small change.
let arr = [];
for (let { Name, Number } of msg.payload) {
arr.push({[ Name ] : Number});
}
msg.payload = arr;
return msg;
Here we use object destructuring inside the for of loop to load the variables Name and Number. Those variables will be used right after to create the modified object. We use also computed properties to generate the new objects (square brackets in the literal object).
Here the Node-RED flow:
[{"id":"199fa305.6b864d","type":"debug","z":"d61a402.f83d6c","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":679,"y":146,"wires":[]},{"id":"4c5fb024.2cac","type":"function","z":"d61a402.f83d6c","name":"Destructuring inside the For of loop ","func":"let arr = [];\n\nfor (let {Name, Number} of msg.payload) {\n arr.push({[Name] : Number});\n}\n\nmsg.payload = arr;\n\nreturn msg;","outputs":1,"noerr":0,"x":448.99999046325684,"y":146.00000190734863,"wires":[["199fa305.6b864d"]]},{"id":"773b7c94.e78794","type":"inject","z":"d61a402.f83d6c","name":"","topic":"","payload":"[{\"Name\":\"name1\",\"Number\":1},{\"Name\":\"name2\",\"Number\":2},{\"Name\":\"name3\",\"Number\":3}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":217.9999828338623,"y":147.9999942779541,"wires":[["4c5fb024.2cac"]]}]
Fourth solution: forEach method
let arr= [];
msg.payload.forEach(elem => arr.push({[ elem.Name ] :elem.Number}));
msg.payload = arr;
return msg;
The idea is the same as the previous solutions. The loop will visit each element of the original array and will have it modified by the callback function. The callback function just push the newly created object to the temporary array.
Node-RED flow:
[{"id":"29f9e29f.974c3e","type":"debug","z":"d61a402.f83d6c","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":555,"y":198,"wires":[]},{"id":"ac334e7d.3faab","type":"function","z":"d61a402.f83d6c","name":"forEach method","func":"let arr= [];\n\nmsg.payload.forEach(elem => arr.push({[elem.Name] :elem.Number}));\n\nmsg.payload = arr;\n\nreturn msg;","outputs":1,"noerr":0,"x":403.9999828338623,"y":196.9999942779541,"wires":[["29f9e29f.974c3e"]]},{"id":"3878f08.c4dc91","type":"inject","z":"d61a402.f83d6c","name":"","topic":"","payload":"[{\"Name\":\"name1\",\"Number\":1},{\"Name\":\"name2\",\"Number\":2},{\"Name\":\"name3\",\"Number\":3}]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":221.9999828338623,"y":196.99999618530273,"wires":[["ac334e7d.3faab"]]}]
No comments:
Post a Comment