Writing a groov table with a single node

OK so, using this:

var m = [];
for (var i in msg.payload.obj.Classes) {
    m.push({payload:msg.payload.obj.Classes[i].Id});
}
return [m];

I get this:

5/29/2021, 11:05:34 AM[node: 168834e3.c099a3](https://192.168.1.90/node-red/#)msg : Object

{ payload: 4311744514, _msgid: "6ba6fc52.bada04" }

5/29/2021, 11:05:34 AM[node: 168834e3.c099a3](https://192.168.1.90/node-red/#)msg : Object

{ payload: 4311744515, _msgid: "6ba6fc52.bada04" }

etc...

How do I use the SPLIT node on this? Nothing I have tried has output any data.

Best as I can see, there is no data in the payload, so hence you are not getting any out.

The payload is the 11 digit number. It shows up as a payload as observed here:

This is directly out of the function block.

Ok, I see it now.

Why are you trying to split? I thought you wanted it in an array?

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)

Ah, Ok, starting to see a little better what you are trying to do.
This covers it nicely:

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:

I would much rather it be something like this:

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?

1 Like

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.

Thanks.

The key is to do the ‘typeof’ check. That’s what looks for your ‘undefined’ and writes a zero in that location.

I think once you put Terrys code in place you should be a lot closer to getting where you want to be.

1 Like

Would you put this into the same function node or create a new function node?
Thanks.

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.

1 Like

When I run this:

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"

Where did I screw up?

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!

1 Like

Excellent! That was it. Thank you.

Sorry, premature celebration.
Now I am getting this error and no writes except the "0"s

Bad request. HTTP response error : 400

Here is the output before the groov write:

6/2/2021, 12:57:41 PM[node: 4b5bfc4d.fb0f1c](https://192.168.1.90/node-red/#)

msg.payload.value : Object

object

tagName: "Class ID"

tableStartIndex: 1

value: object

Url: "http://192.168.1.198:88/api/v0/classes/12901679107"

Id: 12901679107

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.

I figured it out. I needed to look at

msg.payload[i] for ‘undefined’, but write

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)

1 Like