Search documentation

Search for pages in the documentation

Select Many

Flatten arrays into individual items for processing

The Select Many node expands an array into individual items, enabling per-item processing of collections. Use it to iterate over attendees, action items, or any list that needs individual handling.

Overview

PropertyValue
CategoryControl
Node IDds.selectMany.perItem.in1.success1.error0
Input Ports1
Success Outputs1
Error Outputs0
Execution ModePer-item

Configuration

ParameterTypeRequiredDescription
itemsCEL ExpressionYesArray to expand
labelStringNoLabel for each item in output

Items Parameter

A CEL expression that evaluates to an array:

cel
json.meeting.attendees
cel
json.actionItems
cel
json.callRecording.keyStatements

Label Parameter

Optional label for accessing items downstream. If not set, items are at the root of json.

How It Works

text
Input:  { "items": [A, B, C] }
              │
              ▼
        [Select Many]
              │
              ├──▶ Item: A
              ├──▶ Item: B
              └──▶ Item: C

The Select Many node:

  1. Receives input with an array
  2. Extracts the specified array
  3. Emits each element as a separate output
  4. Downstream nodes execute once per element

Input Schema

Expects data containing the array specified in items:

json
{
  "meeting": {
    "attendees": [
      { "name": "John", "email": "john@example.com" },
      { "name": "Jane", "email": "jane@example.com" }
    ]
  }
}

Output Schema

Without Label

Each item becomes the entire json:

json
// First output
{ "name": "John", "email": "john@example.com" }

// Second output
{ "name": "Jane", "email": "jane@example.com" }

With Label

Each item is nested under the label:

Configuration: label = "attendee"

json
// First output
{ "attendee": { "name": "John", "email": "john@example.com" } }

// Second output
{ "attendee": { "name": "Jane", "email": "jane@example.com" } }

Examples

Basic Example: Email Each Attendee

Send individual emails to each meeting attendee.

Workflow:

text
[Load Meeting]
       │
       ▼
[Select Many: json.meeting.attendees]
       │
       ▼
[Email Send] ← Runs once per attendee

Configuration:

  • Items: json.meeting.attendees
  • Label: attendee

Email Send Configuration:

  • To: json.attendee.email
  • Subject: Thank you for attending!

Example: Create Tasks from Action Items

Create individual tasks for each extracted action item.

Workflow:

text
[AI: Extract action items]
         │
         ▼
[Select Many: json.actionItems]
         │
         ▼
[Create HubSpot Task]

Configuration:

  • Items: json.actionItems
  • Label: item

Task Configuration:

  • Title: {{ json.item.task }}
  • Description: Assigned to: {{ json.item.owner | default: "Unassigned" }}

Example: Process Key Statements

Analyze each key statement from a transcript.

Workflow:

text
[Load Meeting]
       │
       ▼
[Select Many: json.callRecording.keyStatements]
       │
       ▼
[If: json.statement.classification == "concern"]
    ├── True ──▶ [Flag for Review]
    └── False ─▶ [Sink]

Configuration:

  • Items: json.callRecording.keyStatements
  • Label: statement

Example: Expand with Context (using Broadcast)

Process items while keeping meeting context.

Workflow:

text
[Load Meeting] ──┬──▶ (meeting data) ─────────┐
                 │                            ├──▶ [Broadcast] ──▶ [Email]
                 └──▶ [Select Many: attendees]┘

Broadcast Configuration:

  • Broadcast: left
  • Left Label: meeting
  • Right Label: attendee

Email Template:

liquid
Hi {{ json.attendee.name }},

Thank you for "{{ json.meeting.title }}".

Example: Nested Array Expansion

Expand arrays within arrays (two Select Many nodes):

Workflow:

text
[Load Data]
     │
     ▼
[Select Many: json.deals]
     │
     ▼
[Select Many: json.deal.contacts]
     │
     ▼
[Email Send]

Note: This creates emails for each contact in each deal.

Best Practices

1. Use Labels for Clarity

Always set a label for readability:

With label:

liquid
{{ json.attendee.name }}
{{ json.attendee.email }}

Without label:

liquid
{{ json.name }}
{{ json.email }}  // Less clear what "json" represents

2. Check Array Existence

Before Select Many, verify the array exists:

text
[If: json.items.size() > 0]
    ├── Yes ──▶ [Select Many] ──▶ [Process]
    └── No ───▶ [Sink]

Or handle empty arrays gracefully.

3. Consider Downstream Volume

Each item creates a separate execution path:

  • 100 attendees = 100 downstream executions
  • Plan for the impact on action nodes

4. Preserve Context When Needed

If downstream needs original context, use Broadcast:

text
[Load] ──┬──▶ [context] ──────────┐
         │                        ├──▶ [Broadcast] ──▶ [Has both]
         └──▶ [Select Many] ──────┘

5. Use Meaningful Array Paths

Be specific about which array to expand:

Specific:

cel
json.meeting.attendees

Ambiguous:

cel
json.items  // What items?

Common Issues

"Cannot iterate over non-array" error

Cause: Items expression doesn't evaluate to an array

Solutions:

  1. Verify the path is correct
  2. Check upstream data actually has the array
  3. Use has() to check existence

No outputs from Select Many

Cause: Array is empty

Solution: Handle empty arrays:

text
[If: array has items?]
    ├── Yes ──▶ [Select Many]
    └── No ───▶ [Handle empty case]

Too many downstream executions

Cause: Large array creating many items

Solutions:

  1. Filter array upstream before Select Many
  2. Limit array size
  3. Use batch processing instead

Lost context after Select Many

Cause: Original data not preserved

Solution: Use Broadcast to attach context:

text
[original] ──┬──▶ [context] ───────────┐
             │                         ├──▶ [Broadcast]
             └──▶ [Select Many: items] ┘
  • Broadcast - Add context to expanded items
  • Zip - Recombine after parallel processing
  • If - Filter items conditionally

Technical Details

Execution Behavior

Per-item execution means:

  • Each array element triggers downstream independently
  • 10 elements = 10 separate downstream executions
  • Order is preserved

Output Count

Number of outputs = length of items array:

  • Empty array → no outputs (downstream doesn't execute)
  • 1 element → 1 output
  • N elements → N outputs

Memory Efficiency

Select Many doesn't duplicate the entire input:

  • Only the specified array is expanded
  • Each output contains one array element
  • Original container data is not included (use Broadcast if needed)

Array Types

Works with arrays of any type:

  • Objects: [{a: 1}, {a: 2}]
  • Primitives: ["a", "b", "c"]
  • Mixed: Not recommended but supported