I want to write these to groov in one shot while also taking care of the dynamic aspect of it. Sometimes there are 5, sometimes there are ten, the size can vary from 1 record to 40 and I need to be able to write zeros (or something) for the null/empty records on the groov. Otherwise I just get errors in node-red about “undefined” records and the corresponding records on the groov remain filled with the previous poll.
Edit: I’m trying to follow @torchard’s instructions/example. He used the function node to build a new JSON array and he used the split node to push all of the records into the groov write node one record at a time. (If I follow correctly)
No, I don’t want a FIFO stream. I want a complete array rewrite every time that can handle a variable (dynamic) length input array and overwrite any empty (undefined) records with a zero (or something) on the groov.
My input array can vary from 1 to 40 records. I use that “classID” to look up statistics for that class in near real-time. I additionally will poll another dynamic array with each ID to display pertinent information regarding that ID at specific locations simultaneously.
I can do it one node at a time, but it’s tedious and harder to catch errors. Also, I haven’t figured out how to deal with undefined records.
This is just the beginning:
Instead of looping through the values you do have, I would recommend looping through all 40 and only write the defined values, otherwise write a placeholder like zero. That way the first 13 (or however many values) will get written and the last 27 still get written to, they just get overwritten with zero instead of some other value.
To make this dynamic and avoid the split node, you can just use node.send({payload : ...}) and an if statement to check to see that the value is good.
Also, note that this node.send() returns individual payloads, so there’s no need for a return statement at the end of the code.
for(i = 0; i < 40; i++) {
// If this value exists, write it to the list:
if(typeof(msg.payload.Classes[i]) !== "undefined") {
node.send({ payload: { tagName : 'id',
tableStartIndex : i,
value : msg.payload.Classes[i] }});
}
// Write zero for undefined values and values not provided by the payload:
else node.send({ payload: { tagName : 'id',
tableStartIndex : i,
value : 0 }});
}
So this would exist right after your “Join” function node and would not rely on a split node. @nickvnlr do you think this is the kind of approach that you’re looking for?
I got this to work yesterday on a smaller array with the split node, but it still doesn’t overwrite undefined values.
var sentence = msg.payload.obj.ExitIds; // Some table/array of data.
var data = []; // A new array to hold the tag, indices, and values for groov.
for (i = 0; i < sentence.length; i++) // Go through the list
{
data.push({
tagName : 'TestArray',
tableStartIndex : i,
value : (sentence[i])+1
}); // Each 'data' object will be one groov write
}
return { payload : data }; // This new array is the payload, soon to be split!
I’ll play with the new coding and see where I get. At some point when I get more time I will put together a “Dummies” version of all of this. I am not a programmer by trade and had to fumble my way through this.
Whatever works best for you, honestly either way is fine. You may find it easier to modify and debug if it’s a separate node, but it might be easier to work on if you can see all the code at once.
It’s more personal preference than a real functional difference since all the code is going to run either way.
var sentence = msg.payload.obj.Classes; // Some table/array of data.
var data = []; // A new array to hold the tag, indices, and values for groov.
for (i = 0; i < sentence.length; i++) // Go through the list
{
data.push({
tagName : 'Class ID',
tableStartIndex : i,
value : sentence[i]
}); // Each 'data' object will be one groov write
}
return { payload : data }; // This new array is the payload, soon to be split!
and then this:
for(i = 0; i < 40; i++) {
// If this value exists, write it to the list:
if(typeof(msg.payload[i]) !== "undefined") {
node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : msg.payload[i] }});
}
// Write zero for undefined values and values not provided by the payload:
else node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : 0 }});
}
and inject msg.payload.value.value.Id into groov write I get results plus this error:
6/2/2021, 12:00:56 PM[node: Class 0](https://192.168.1.90/node-red/#)
msg : string[38]
"Cannot read property 'Id' of undefined"
It should just be msg.payload.value in the groov write node, since that’s what you are returning in this object:
node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : msg.payload[i] }});
This will send a msg object that has one property, the payload. The payload has three subproperties; tagName, tableStartIndex, and value.
So you just want to grab this msg.payload.value and stop there – that value property has no subproperties, so msg.payload.value.value is undefined, and then you get the error on the property Id because you can’t get a property of an undefined object.
Hopefully that makes some sense and gets you up and running!
If I join them together like this all I get is the 0’s.
var sentence = msg.payload.obj.Classes; // Some table/array of data.
var data = []; // A new array to hold the tag, indices, and values for groov.
for (i = 0; i < sentence.length; i++) // Go through the list
{
data.push({
tagName : 'Class ID',
tableStartIndex : i,
value : sentence[i]
}); // Each 'data' object will be one groov write
}
//return { payload : data }; // This new array is the payload, soon to be split!
for(i = 0; i < 41; i++) {
// If this value exists, write it to the list:
if(typeof(msg.payload[i]) !== "undefined") {
node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : msg.payload[i] }});
}
// Write zero for undefined values and values not provided by the payload:
else node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : 0 }});
}
When the code is combined and ran back-to-back like this your data is not in msg.payload[i] anymore, it’s in data[i]. It was only in msg.payload as an array becuase you returned it from the previous node when you did return { payload : data }
It can still work if the code is combined like this, you just need to be mindful of variable names when moving code around into different scopes and make sure it’s consistent.
If that fix isn’t enough, I would start by doing some deeper, more specific debugging with node.warn(); (You can see more about logging events on this page: https://nodered.org/docs/user-guide/writing-functions.)
For example, is sentence being correctly filled with the values you expect?
You could check that before the loop with node.warn(sentence[0]); or even node.warn(sentence[i]); inside the first loop, or check data[i] further down, depending on where it goes bad. Narrowing down the line that things go wrong is a really important part of debugging.
Also, I noticed you’re going from i=0 to i<41 in the second loop – that is a total of 41 values including 0, not 40 – which is OK if you have that many indexes in your groov array, I just wanted to point it out incase that was unintentional.
msg.payload[i].value.Id as a value. So the second node looks like this:
for(i = 0; i < 41; i++) {
// If this value exists, write it to the list:
if(typeof(msg.payload[i]) !== "undefined") {
node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : msg.payload[i].value.Id}});
}
// Write zero for undefined values and values not provided by the payload:
else node.send({ payload: { tagName : 'Class ID',
tableStartIndex : i,
value : 0 }});
}
Yes, the 0 to 41 was on purpose so I could start at slot 1 and fill to slot 40.
(actually thanks for the catch, I needed to start at i=1)