# Process a list | Docs - nodulz

Source: https://nodulz.com/docs/working-with-lists

Language: en

You receive several contacts and want to prepare a message for active contacts only. This walkthrough starts with a list, removes one contact, then builds one result per remaining contact. No email is sent and no external credential is needed.

## Choose between IF, Filter and Loop

- **IF** chooses an execution path. Use it for a decision such as “is this request complete?”.
- **Filter** keeps selected items in a list. It returns a shorter list without running an action for each item itself.
- **Loop over items** runs processing for each item or batch. Its **Done** output continues the workflow after iteration.

> [!FLOW] From three contacts to two prepared messages
>
> 1. **Manual** <!-- node: manual -->
>    Three contacts: Ada, Lin and Sam.
> 2. **Filter: active** <!-- node: filter -->
>    Keeps Ada and Sam. Removes Lin.
> 3. **Loop** <!-- node: loop -->
>    Two turns, two prepared messages.

## Supply the starting data

Paste this into the **Test payload** of a [Manual trigger](/docs/nodes/manual):

```json
{
  "contacts": [
    { "name": "Ada", "email": "ada@example.test", "active": true },
    { "name": "Lin", "email": "lin@example.test", "active": false },
    { "name": "Sam", "email": "sam@example.test", "active": true }
  ]
}
```

`input.contacts` is the complete list; `input.contacts[0]` is its first contact. Keep boolean values `true` and `false` unquoted in this JSON.

## Keep active contacts

Add [Filter](/docs/nodes/filter) after the trigger and configure:

- Source: `input.contacts`.
- Condition field: `active`.
- Operator: **Equals** (`equals`).
- Comparison value: `true`.

The source identifies the list within the workflow. The condition field is read inside each contact: enter `active`, rather than `input.contacts.active`.

Run and check this output:

```json
{
  "items": [
    { "name": "Ada", "email": "ada@example.test", "active": true },
    { "name": "Sam", "email": "sam@example.test", "active": true }
  ],
  "count": 2,
  "removed": 1,
  "combinator": "and"
}
```

Later steps should read the `items` property for the filtered list. Names `filter1`, `loop1` and `set1` below are examples: use the technical names shown in your mapping.

## Prepare one message per contact

1. Add [Loop over items](/docs/nodes/loop_over_items) after Filter. Set its source to `nodes.filter1.items` and keep `batchSize` at `1`.
2. From **Loop**, connect [Edit fields](/docs/nodes/set). Enable **Mapped fields only**.
3. Create `email` with `{{ nodes.loop1.item.email }}` and `message` with `Hello {{ nodes.loop1.item.name }}`.

> [!LOOP] One message per contact, then Done
>
> 1. **Loop over items** <!-- node: loop -->
>    Is there another contact to process?
> 2. **Loop** <!-- node: set -->
>    Prepares a message and repeats.
> 3. **Done** <!-- node: data -->
>    Results in `items`.

Run the complete workflow again. Final loop output should be:

```json
{
  "items": [
    { "email": "ada@example.test", "message": "Hello Ada" },
    { "email": "sam@example.test", "message": "Hello Sam" }
  ],
  "count": 2
}
```

## Continue once the list is complete

Connect another Edit fields node to the loop’s **Done** output. Enable **Mapped fields only** and create `processed` with `{{ nodes.loop1.count }}`.

This node should run after both contacts are processed and produce `{ "processed": 2 }`. Do not connect it to Loop: it would count turns during processing instead of reading the final result.

## Check cases that lose data

- **All contacts are inactive**: Filter returns `count: 0`. The loop body should not run; Done should produce a total of zero.
- **The same contact appears twice**: this chain does not deduplicate data. Add [Remove duplicates](/docs/nodes/remove_duplicates) before the loop if your business rule requires it.
- **Every message uses Ada**: you probably read `input.contacts[0]` again. Use `nodes.loop1.item` for the current item.
- **Fields disappear after an IF**: its output describes the comparison. Explicitly read the output of the node holding the list instead of relying on implicit forwarding.

To actually send these messages, replace preparation with the appropriate sending node or add it inside the body. Check its access and a test destination before using the real list.

## Explore further

- [Features - nodulz](https://nodulz.com/product/overview)
- [Node catalog - nodulz](https://nodulz.com/product/catalog)
- [MCP server - nodulz](https://nodulz.com/product/mcp)
- [Pricing - nodulz](https://nodulz.com/pricing)
- [Use cases and workflow automation - nodulz](https://nodulz.com/use-cases)
- [Choose what your workflows can do. - nodulz](https://nodulz.com/compare)
- [Documentation - nodulz](https://nodulz.com/docs)
