Regex in a node - "TypeError: msg.payload[0].match is not a function"

Hi all, I'm going crazy with this one.
I already have a function setup and working using the .match in function node with zero issues (See Below:)

const channel_no_regex = /(?<=\()[A-Z][0-9][^)]*(?=\))/gm;
const channel_no = msg.payload.match(channel_no_regex);
const channel_name = msg.payload.match(/(?<=\W )[a-zA-Z 0-9]+(?=\()/gm)
const event_type = msg.payload.match(/(?<=TYPE: ).*(?=\n)/gm)
const event_time = msg.payload.match(/(?<=TIME: ).*(?=\n)/gm)
if(channel_no_regex != null){
    msg.ch = channel_no;
    msg.chname = channel_name; //CHANGE THIS TO '0' NORMALLY. 1 IS JUST FOR TESTING DUE TO NL
    msg.event = event_type[0];
    msg.time = event_time[0];
    return [msg, null];
}else{
    return [null,msg]
}

I'm trying to build another function using regex and keep getting the error “TypeError: msg.payload.match is not a function”

I've tried everything I can think of. Below is what I have currently. Nothing works.

//const regex = /(?<=").[^"]+(?=")/gm;
//const match = msg.payload.match(/(?<=").[^"]+(?=")/gm)
var words = msg.payload.match(":");
//msg.match = match;

msg.words = words;

return msg;

Nothing I try works and I'm going crazy trying to work out why. Any suggestions would be very welcome. Thank you!

That is not the same error as in the thread title. Which is right?

If you get the error something.match is not a function that means that the something is not of a type that it is valid to call match on. Feed the function input into a debug node and check what it says.

The only difference is the [0].
My input is a CSV parser and i tried with both 'one output per line' enamoured and disabled. When disabled it outputs an array hence having the [0] when that option is disabled.

I'll pay a screenshot of the input as soon as I'm back to my pc. It's something along the lines of:
"Col 1: " "x"
"Col 2: " "o"
"Col 3: " "x"

Etc.

Thank you.

Is there "really" a need for all the regex ? What does the input data look like ?

If you get an error "{anything}.match is not a function" then that means that {anything} is not an object that has a method called match, i.e. a string in your case. {anything} could be null, or it could be a number, or it could be an array, or ...

The upshot is that (a) you need to guard all your stuff with a check like

if (typeof msg.payload === 'string') { ... }

and (b) you may want to print what other types of payloads come along so you can understand whether that's OK or there's something else fishy going on, so add to the above guard a

else { node.warn(`unexpected payload ${msg.payload}`) }

If that is what is in msg.payload, then you can't do msg.payload.match because msg.payload is not a string.

As @bakman2 asks, is all this really necessary?. What exactly are you trying to do with that payload?

Are you sure it isnt more like ...

{
  "Col 1": "x"
  "Col 2": "o"
  "Col 3": "x"
}

in which case this is JSON and can be converted to an object (using the JSON node) and then you can simply address the items like this msg.payload["Col 1"]

Thanks for all the replies! I can't work out how to quote individual messages so my replies are below:

@All - the actual project is essentially an input/output controller which I intend to use for various IO Projects. My goal is to have a table as shown below which will have each row representing an input, and each column representing an output. in the box where the input and output meet, an X will mean that the output triggers when the input is active. I may possibly have other functions such as P(Pulse), O(off), 180(on for 180 seconds then off), I(Invert), etc.

I had thought that the best way to do this was with an array of arrays. X axis would be outputs, and Y would be inputs. So for example, 'smoking shelter carpark camera detection' would trigger arrayX[3] which would scan through and then trigger the corresponding output functions.

The whole idea of the node is that it will be modular, easy and simple to modify and copy to other projects.

Ultimately, I'd like a table in the UI which will show a visual representation of the Cause/Effect schedule but I still need a way to keep the data saved. To do this, I thought using a CSV file would be best. Here is where I'm running into my current issue.

@bakman2 - I'm not sure if there 'really' is a need. I'm still relatively inexperienced with node-red and I'm mainly doing little projects where I can try and get familiar with different programming methods and approaches. I thought regex would be best to extract the varying data that I need in order to put it into arrays. I like to keep my flows as 'small' as possible, ideally using one function node instead of many split, join, change etc nodes.

@tve Thank you! I was pulling hair out as I thought the issue was with .split but the incorrect data makes total sense. I think I'm perhaps reading the debug incorrectly. The main confusion is coming from 'col1' 'col2' etc which I think are coming from the 'csv parse' node, I'd thought this was all a string but now I'm thinking maybe not?

@Steve-Mcl I think you've hit the nail on the head there! JSON is still something I'm less familiar with so This is almost certainly the answer. Thank you very much. I'll report back with my progress.

@All:
Here's the output of the debugger

I dont see the connection with the original post, but to make these arrays "easier" to read, check this checkbox in the csv node - get rid of the enters in the cause/effect - better yet, use sensible namings without spaces (use _ instead, or camelCase) for all colums and use true/false instead of o/x:

image

Once an item is an object, you can use the "copy path" and "copy value" tools provided by the debug pane.

Canned Text...

There’s a great page in the docs (Working with messages : Node-RED) that will explain how to use the debug panel to find the right path to any data item.

Pay particular attention to the part about the buttons that appear under your mouse pointer when you over hover a debug message property in the sidebar.

BX00Cy7yHi

Can you paste the raw data you're trying to put into that table?

Hello again everyone and thanks again for all the help!

This is just a 'toy project' intended to help me learn node-red (Although it will have real world use!)

Thanks to your words, I've now learned about objects which is great, and I also ended up finishing (this part of) the project.

I got rid of the CSV parser and instead wrote a function node to split my CSV file into a 2d array.

This is working great for me for now! I'll no doubt have more questions but I thought it would be good to pop back and let you know.

Thanks again :slight_smile:

const rows = msg.payload.match(/^[^\n]+/gm);
//const columns = [];
//var cLength = rows[0].split(/,/gm).length; //see it this works. may need to split to two lines.
var cLength = rows[0].split(/,/gm);
var amount = cLength.length;
var output = [];
var io = [];

//msg.split = rows[0].split(/,/gm);

for (let i=0; i < rows.length; i++) { //cycle through each ROW
    //const column = rows[i].split(/,/gm);
    output[i] = [];
    output[i] = rows[i].split(/,/gm);
}


flow.set("io", output);
msg.output = output;
msg.rows = rows;
return msg;

I got rid of the CSV parser and instead wrote a function node to split my CSV file into a 2d array.

Which 2 csv parsers could have done as well. General reminder: the idea of node-red is low-code.
Writing functions is not "learning node-red", it is learning javascript.

As long as folk are learning, that is good.

1 Like