Either dumb question or possible suggestion for the Change node

I find myself frequently dragging a Change node onto the canvas, only to delete it and write a JS function to do the same thing, because the change node can't do the job I'm trying to do (as far as I know). That job is any standard array method like push, pop, shift, or unshift, as well as prepending or appending a string to a string (as similar undertaking).

Frankly, just being able to "push" to an array or append to a string would be plenty for most purposes, and I have nothing against writing a line of JS to do this in a Function node, but for some reason, it always seems like there should be an item in the drop-down that says "Add" (like it currently says "Set", "Change", "Delete", and "Move"), which pushes the value to an array; appends a string to a string; adds a number to a number; adds a key/value pair to an object; etc. I suppose each of those data types except numbers could ask whether it was intended to append or prepend, but you get the idea.

I'm aware that you can do this via JSONata inside the Change node, but at that point, you might just as well use a Function node instead.

Maybe I'm missing why this would be a useful part of the basic Change node, or maybe I'm totally oblivious to the basic and straightforward way of doing this.

Thoughts?

Have you thought about looking in the flow library for a node that might help like this one: collection-red (node) - Node-RED

Not a dumb thought at all... - My simplistic thoughts are that most often when I want to do array type things the very next line is to check the length and trim it (or whatever) - so it's never really just a simple add etc, so would just the basic actions really be sufficient in the change node. (Maybe or maybe not - certainly worth a thought).

But as @zenofmud indicates maybe another node may help (as indeed that does seem to be well specd)

I've learnt to use template node for simple string prepend/append stuff

But would love to see it in the change node :slight_smile:

2 Likes

Thanks for the reply, @dceejay! I totally agree that as @zenofmud suggests, there are other nodes that can accomplish this job - the thought was more that, for whatever reason, I keep expecting to be able to do something so basic with the Change node.

Most likely, due to my self-taught relationship (that is, general inexperience) with JS, I just am not using arrays right, since those next steps you refer to (trim, get the length into a separate variable, etc.) aren't things I have to do too often - I iterate through arrays just using i=0;i<myArray.length;i++, for example. I just wanted to bring it up in case someone might say, "Why didn't you just scroll down to 'Append' in the drop-down inside the Change node?" or "Wow, why haven't we thought of that? I (or new users) would use that all the time!".

If you didn't say (some version of) either of those two things, then absolutely feel free to stop reading right here, and have nice day! :grin: Most likely, I should just use a different node like Function, like someone who knows what they're doing. (I will admit that the Collection node doesn't seem like a great option since there's no inherent order to the "key1", key2", etc., unlike an array where you can at least choose the last element, no matter how long it is; so I think I'd stick with a simple Function for this purpose. It's even already installed on all my Node Red instances!)

=================

If it's useful: The last time I wanted to do this, I was looking up the names of all the DS18B20 temperature sensors that were connected to a RPi. I have a lot of these Pi's each with a handful (3-15) of sensors attached, so I thought once and for all, I should create a little routine that looks up all the addresses of the connected sensors and puts them in an array in the global context (and in the msg object), so that I can iterate through them for reading, rather than hardcoding the addresses by hand for each install, for the 47th time.

It would be pretty easy to just do this all in one big Function node, but I'm trying to cut back on Function nodes and only use them when there isn't an existing Node Red node for that job, so that my work is more visual when I come back to it in 2 years and have to work on it. Here's the flow, including the Debug output after having deleted the old list:

So, I get a string from the exec node output which lists the addresses separated by newlines (shown in the first debug), I Split it based on newline, and Switch the outputs based on whether they contain "28-" (as all Dallas sensors of this type start with). Now I have a nice little series of messages, each containing a string payload of a valid address, e.g. "28-11a22b33c44d55e" - for example, a series of 5 of those, coming out of that second Debug node.

(Note that I could turn this directly into an array with the Split node, but there are a couple reasons not to do that immediately - I need to filter out things that don't start with "28-", and may be appending just one new address to the existing array of addresses, rather than simply appending everything I find.)

It's the Function node here that represents the spot where I keep dragging the Change node in, only to remember that "append" or "add" or etc. isn't something it does, which might be helpful to no-code new users trying to perform a basic operation like appending strings or pushing to an array. This is literally all it does:

msg.IDlist.push(msg.payload);
return msg;

The final Debug node just represents the output of this operation, which goes off to get any known "names" for these sensors, then read them, put the readings in global context, and tell thermostat functions to update based on new readings, etc.

Here's the flow, in case my labels aren't clear:

[{"id":"13c4eeb49f9285c4","type":"exec","z":"159c98d1.b0c3e7","command":"cd /sys/bus/w1/devices && ls","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":2740,"y":1020,"wires":[["fafe3421ce28c477"],[],[]]},{"id":"12fa9030fcc6110b","type":"inject","z":"159c98d1.b0c3e7","name":"keep old","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"old","v":"keep","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":2500,"y":1020,"wires":[["13c4eeb49f9285c4"]]},{"id":"05c07a7f73f219c5","type":"change","z":"159c98d1.b0c3e7","name":"clear list","rules":[{"t":"set","p":"sensors.temp.IDlist","pt":"global","to":"[]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":2680,"y":960,"wires":[["13c4eeb49f9285c4"]]},{"id":"fafe3421ce28c477","type":"split","z":"159c98d1.b0c3e7","name":"split \"/n\"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":2860,"y":1100,"wires":[["0da8df829170d34a"]]},{"id":"5487d45e7eeff6e4","type":"inject","z":"159c98d1.b0c3e7","name":"delete old","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"old","v":"delete","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":2500,"y":960,"wires":[["05c07a7f73f219c5"]]},{"id":"0da8df829170d34a","type":"switch","z":"159c98d1.b0c3e7","name":"switch if contains \"28-\"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"28-","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":2900,"y":1160,"wires":[["ed3cfa4fe31382dd"]]},{"id":"ed3cfa4fe31382dd","type":"change","z":"159c98d1.b0c3e7","name":"get existing list from global","rules":[{"t":"set","p":"IDlist","pt":"msg","to":"sensors.temp.IDlist","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":2920,"y":1220,"wires":[["9905b83d87ac136f"]]},{"id":"9905b83d87ac136f","type":"switch","z":"159c98d1.b0c3e7","name":"return if sensor missing from global","property":"IDlist","propertyType":"msg","rules":[{"t":"cont","v":"payload","vt":"msg"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":2940,"y":1280,"wires":[[],["3a65ff518f298da2","3d8331e7321c5da4"]]},{"id":"3a65ff518f298da2","type":"function","z":"159c98d1.b0c3e7","name":"push to list and set payload to new list","func":"msg.IDlist.push(msg.payload);\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":3270,"y":1280,"wires":[["fe96fa25f29fafac"]]},{"id":"3d8331e7321c5da4","type":"debug","z":"159c98d1.b0c3e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":3210,"y":1180,"wires":[]},{"id":"fe96fa25f29fafac","type":"change","z":"159c98d1.b0c3e7","name":"","rules":[{"t":"set","p":"sensors.temp.IDlist","pt":"global","to":"IDlist","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":3260,"y":1340,"wires":[["dd913468dda925ef"]]},{"id":"dd913468dda925ef","type":"trigger","z":"159c98d1.b0c3e7","name":"pass only final list after 250ms","op1":"","op2":"sensors.temp.IDlist","op1type":"nul","op2type":"global","duration":"250","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":3270,"y":1400,"wires":[["5b2835759d7f43ac"]]},{"id":"5b2835759d7f43ac","type":"debug","z":"159c98d1.b0c3e7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":3350,"y":1460,"wires":[]}]