How to implement loops in Node-RED flows

Handling repetitive tasks is a common challenge in automation and data processing. Whether you need to iterate over large datasets, perform calculations, or execute operations based on conditions multiple times, using loops can significantly enhance efficiency and scalability.

In this document, we’ll explore how to replicate different types of loops that are essential in various contexts. We’ll discuss their applications and provide examples to help you effectively implement them in Node-RED.

What is a Loop?

A loop is a programming construct that allows you to execute a block of code repeatedly until a certain condition is met. Different types of loops are suited to different scenarios, depending on how and when you want the code to repeat:

  • For Loop: Executes a block of code a specific number of times. This is useful when you know in advance how many times you need to iterate, such as iterating through a range of numbers or items in a list. It's also known as a fixed number loop.

  • While Loop: Repeats a block of code as long as a specified condition is true. This type of loop is useful when you don’t know how many times the loop will need to run beforehand. The loop continues executing until the condition becomes false.

  • For...of / ForEach Loop: These loops are used to iterate over iterable objects such as arrays or maps. They allow you to access each element in a collection. The for...of loop is used specifically for iterables, while forEach is a method available on arrays that applies a function to each element.

Each type of loop serves a different purpose and can be chosen based on the requirements of the task at hand.

Implementing Loops in Node-RED

In this section, we’ll explore how to implement loops in Node-RED. First, we’ll demonstrate how to achieve looping with core nodes. Then, we’ll show how to accomplish similar tasks using custom nodes. We’ll also cover some essential operations typically performed using loops, providing practical examples to enhance your Node-RED flows.

Implementing Loops in Node-RED with Core Nodes

While Loop

To demonstrate a while loop in Node-RED, we’ll create a flow that appends random characters to a string until it contains the character "Z". This example will help you understand how to simulate a while loop using Node-RED's core nodes.

  1. Drag an Inject node onto the canvas. This node will trigger the start of the loop.
  2. Add a Change node to initialize the string variable. Configure it to set msg.i to an empty string (""). Connect the Inject node to this Change node.
  3. Place a Switch node on the canvas. Set it to check if msg.i contains the character "Z" (msg.i.includes('Z')). Add an additional rule for when this condition is not met (otherwise). Connect the output of the Change node to the input of the Switch node.
  4. Add a Function node to append a random uppercase letter to the string. Use the following JavaScript code:
    msg.i += String.fromCharCode(65 + Math.floor(Math.random() * 26)); // Append a random uppercase letter
    return msg;
    Connect this Function node to the second output of the Switch node (where the condition is msg.i does not contain "Z"). Then, connect the output of this Function node back to the input of the Switch node to repeat the process.
  5. Drag a Debug node onto the canvas and connect it to the second output of the Switch node. This node will display the current value of msg.i in the debug panel.
  6. Add another Change node to signal completion. Configure it to set msg.payload to "completed". Connect this Change node to the first output of the Switch node (where msg.i contains "Z"), and then link it to another Debug node to show the completion message.

The flow will continuously append random letters to the string and print the value in the debug panel until the string contains "Z". Once the condition is met, the flow will print a "completed" message and terminate the loop.

graph TD
    A["Inject Node<br>Triggers the start of the loop"] --> B["Change Node<br>Initialize String<br>Sets msg.i = ' '"]
    B --> C["Switch Node<br>Check if msg.i contains 'Z'"]
    C -->|"msg.i contains 'Z'"| D["Change Node<br>Set msg.payload to 'completed'"]
    D --> E["Debug Node<br>Display Completion Message"]
    C -->|"msg.i does not contain 'Z'"| F["Function Node<br>Append Random Character<br>Sets msg.i += random uppercase letter"]
    F --> C
    F --> G["Debug Node<br>Display Current String"]

For Loop

In traditional programming, for loops iterate a set number of times based on an index or range, while while loops execute as long as a condition is true.

In Node-RED, you can simulate a for loop by managing a counter with nodes to iterate through array elements. By incrementing an index variable, you can access each element and perform operations, effectively mimicking the behavior of a traditional for loop.

Here’s how you can set up a for loop in Node-RED:

  1. Drag an Inject node onto the canvas and set the msg.payload to ["foo","bar","foobar"]. This node triggers the start of the loop and provides the array to process.
  2. Add a Change node to initialize the loop counter. Configure it to set msg.i to 0, and connect the Inject node to this Change node.
  3. Next, drag a Switch node onto the canvas. Configure it to check if msg.i is equal to the array length (msg.i == msg.payload.length). Add an additional rule for when this condition is not met (otherwise). Connect the Change node to the Switch node.
  4. Add another Change node to increment the counter. Configure it to set msg.i to i + 1 using a JSONata expression. Connect this Change node to the output of the Switch node where the condition (msg.i < msg.payload.length) is true (second output).
  5. To access and display the array elements, drag a Change node onto the canvas. Configure it to set msg.payload to msg.payload[msg.i], accessing the array element at the current index. Connect this Change node to the Switch node's second output (otherwise).
  6. Attach a Debug node to the output of this Change node to print the current array element.
  7. For the final step, add another Change node to signal when the loop has completed. Configure it to set msg.payload to completed, and connect it to the first output of the Switch node where the loop condition is msg.i == msg.payload.length. Finally, attach a Debug node to display the completion message.

This flow will iterate through the array, printing each element until all elements have been processed. Once the loop reaches the end of the array, it prints a "completed" message and terminates.

graph TD
    A["Inject Node<br>Sets msg.payload to array"] --> B["Change Node<br>Initialize Counter<br>Sets msg.i = 0"]
    B --> C["Switch Node<br>Check if msg.i == msg.payload.length"]
    C -->|"msg.i < msg.payload.length"| D["Change Node<br>Increment Counter<br>Sets msg.i = msg.i + 1"]
    D --> E["Change Node<br>Access Element<br>Sets msg.payload = msg.payload[msg.i]"]
    E --> F["Debug Node<br>Display Current Element"]
    C -->|"msg.i == msg.payload.length"| G["Change Node<br>Loop Completion<br>Sets msg.payload = 'completed'"]
    G --> H["Debug Node<br>Display Completion Message"]

For...of / ForEach Loop

In traditional programming, for...of and forEach loops are commonly used to iterate through arrays or object properties, allowing for individual element processing. Since Node-RED doesn’t include these specific constructs, you can replicate their functionality by using a combination of nodes, particularly the Split and Join nodes.

Here’s how you can replicate this functionality in Node-RED:

  1. Drag an Inject node onto the canvas and set the msg.payload to ["foo", "bar", "foobar"].
  2. Drag a Split node onto the canvas. Keep the default settings. If you are working with a string, ensure you select the appropriate delimiter for splitting.
  3. Optionally, use a Change or Function node to perform operations on each element if needed.
  4. Drag a Debug node onto the canvas and connect it to the Split node’s output.

When you click the Inject button, the Split node will process each element of the array individually, and the Debug node will display each one in the debug window.

To explore how you can map, sort, filter, and reduce data using this approach, check out our guide: How to Filter, Map, Sort, and Reduce Data in Node-RED.

graph TD
    A["Inject Node"] --> B["Split Node"]
    B -->|Outputs Each Element Individually| C["Debug Node"]
    
    A["Inject Node\nSets msg.payload to array"]
    B["Split Node\nSplits array into individual elements"]
    C["Debug Node\nDisplays each element"]

Implementing Loops with the Function Node

Implementing loops with the Function node is straightforward if you're familiar with JavaScript, as it allows you to write custom code. However, a common issue is figuring out how to send a message on each iteration without ending the loop after the first iteration. In this section, we’ll show you how to implement loops in the Function node correctly, ensuring that each iteration is processed and sent out properly without prematurely breaking the loop.

For demonstration purposes, we will implement a for loop.

  1. Drag the Inject node onto the canvas and set the msg.payload to [1, "hello", "%", true].
  2. Drag the Function node onto the canvas and add the following JavaScript code:
    for (let i = 0; i < msg.payload.length; i++) {
    // Create a new message for each item
    let newMsg = { ...msg }; // Copy the original msg object
    newMsg.payload = msg.payload[i]; // Set payload to the current item
    node.send(newMsg); // Send the message
    }
  3. Drag a Debug node onto the canvas and connect it to the output of the Function node.

When you deploy the flow and click the Inject button, each item in the array will be sent as a separate message and printed in the debug panel. This works because the node.send() method allows you to send messages asynchronously. Unlike return, which ends the execution of the Function node immediately, node.send() continues to process and send each message without halting the loop.

By using node.send() inside the loop, you ensure that each iteration produces a separate message, and the Function node can handle multiple messages efficiently. For more information on on this, refer to Documentation on Sending messages asynchronously.

Implementing Loops in Node-RED with Custom node

Throughtout this section we will show you how you can implement loops in Node-RED with custom nodes easily, there are plenty of custom nodes that can be used to achieve the loop but we will going use the popular one node-red-contrib-loop, before moving further make sure to install it by palette manager also for demostration purpose we will use same example we used in the above sections with loops.

While Loop

  1. Drag the Inject node onto the canvas.

  2. Drag the Loop node onto the canvas, double-click it, and set the kind to Condition. Set the condition to msg.payload.includes("Z") != true as JavaScript. The condition kind offers a lot of flexibility as it allows adding conditions in JavaScript, regex, and JSONata.

  3. Set the "When test" option:

  • Choose "after" if you want the loop to execute at least once before checking the condition, similar to how a while loop operates when it checks the condition after the first iteration.
  • Choose "before" if you want the loop to check the condition before executing, functioning like a traditional while loop that only runs if the condition is true at the start.
  1. Drag the Function node onto the canvas. Add the following JavaScript code to it and connect its input to the second output of the Loop node:

    msg.i += String.fromCharCode(65 + Math.floor(Math.random() * 26)); // Append a random uppercase letter
    return msg;
  2. Drag the Delay node onto the canvas, set the delay to 0.5 milliseconds. When using the condition kind of loop, it is important to use the Delay node with this loop custom node to avoid creating an infinite loop. Connect the Delay node's input to the output of the Function node, and connect its output to the input of the Loop node.

  3. Drag a Debug node onto the canvas and connect its input to the output of the Function node. This will print the current msg.payload after each iteration.

  4. Drag another Debug node onto the canvas and connect its input to the first output of the Loop node. This will print when the loop exits, indicating that the condition has been met.

For Loop

  1. Drag an Inject node onto the canvas and set the msg.payload to ["foo", "bar", "foobar"]. This node will trigger the start of the loop and provide the array we want to process.
  2. Drag a Change node onto the canvas. Configure it to set msg.count to msg.payload.length, which will store the length of the array. Connect the Inject node to this Change node.
  3. Drag a Loop node onto the canvas, double-click on it, and set the kind to Fixed. Leave the "count" field empty as we are setting it dynamically using msg.count. Set the initial value to 0 and the step value to 1. Set the loop payload to the original msg.payload.
  4. Next, drag a Change node onto the canvas and configure it to either clear or set msg.payload to itself. This ensures that the payload remains unchanged. Connect its input to the output of the Loop node and then connect its output back to the input of the Loop node. This setup allows the loop to repeat.
  5. Then, drag another Change node onto the canvas. Configure this node to set msg.payload to msg.payload[msg.loop.value], which extracts the current array element using the loop’s counter (msg.loop.value). The Loop node generates properties like value, which is the counter we are incrementing.
  6. Finally, drag a Debug node onto the canvas and connect it to the output of the previous Change node to print the current array element in each iteration.

For...of / ForEach Loop

  1. Drag an Inject node onto the canvas and set the msg.payload to [6, 14, 36, -8, 100]. This node will trigger the loop and provide the array of numbers to process.
  2. Drag a Loop node onto the canvas. Set the Kind to Enumeration and choose msg.payload as the enumeration source. This configuration will loop through each value in the array. Set the "loop payload" to the "value".
  3. Drag a Change node onto the canvas and configure it to either clear or set msg.payload to itself. This ensures that the payload remains unchanged during each iteration. Connect its input to the second output of the Loop node, then connect its output back to the input of the Loop node to create the loop.
  4. Finally, drag a Debug node onto the canvas and connect it to the second output of the Loop node. This will display the current value being processed in the loop.

With the Enumeration kind, you can iterate through different types of data such as arrays, strings, objects, and more, making this loop versatile for handling various data structures.