Skip to main content

Switch Control Node

Overview

The Switch control node is a multi-branch conditional processing node that routes data to different branches for execution based on the result of an expression evaluation. It supports complex condition evaluation and multiple matching modes, making it a core control node for implementing complex business logic branching.

Node Configuration

Basic Properties

{
"id": "switch-1",
"type": "control",
"config": {
"identifier": "switch",
"title": "Condition Router",
"description": "Multi-branch conditional processing"
}
}

Input Parameters

ParameterTypeRequiredDescription
dataObject/AnyInput data used for expression evaluation
expressionStringCondition expression, supports JavaScript expressions
casesArrayArray of branch cases, each containing a value and port
defaultCaseObjectDefault branch, executed when no case matches

Branch Case Structure

{
"cases": [
{
"value": "A", // Match value
"port": "gradeA" // Output port name
},
{
"value": ["VIP", "GOLD"], // Supports array matching
"port": "premium"
}
],
"defaultCase": {
"port": "default" // Default port
}
}

Expression Evaluation

The Switch node uses ConditionEvaluator to evaluate expressions, supporting:

Basic Expressions

// Simple property access
"data.score"
"data.user.level"

// Numeric comparison
"data.score >= 90"
"data.amount > 1000"

// String matching
"data.status === 'active'"
"data.type"

Compound Expressions

// Ternary operator
"data.score >= 90 ? 'A' : data.score >= 80 ? 'B' : 'C'"

// Logical operations
"data.amount > 1000 && data.customer.vip"
"data.type === 'URGENT' || data.priority === 'HIGH'"

// Complex condition combinations
"data.amount > 1000 && data.customer.vip ? 'VIP_LARGE' : data.type === 'URGENT' ? 'URGENT' : 'NORMAL'"

Matching Modes

The Switch node supports three matching modes:

1. Exact Match

{
"cases": [
{ "value": "A", "port": "excellent" },
{ "value": "B", "port": "good" },
{ "value": 90, "port": "highScore" }
]
}

2. String Match (Case-Insensitive)

{
"cases": [
{ "value": "pending", "port": "waitingHandler" },
{ "value": "RUNNING", "port": "activeHandler" }
]
}
// Both "PENDING" and "pending" will match waitingHandler

3. Array Inclusion Match

{
"cases": [
{ "value": ["DIAMOND", "PLATINUM", "GOLD"], "port": "premium" },
{ "value": ["SILVER", "BRONZE"], "port": "standard" }
]
}
// When data.level is "GOLD", it will match the premium port

Context Management

The Switch node saves execution results in the context:

// Context structure
context['switch-1'] = {
[matchedPort]: inputData, // Data corresponding to the matched port
'_switch_result': {
expression: "data.score >= 90 ? 'A' : 'B'",
expressionValue: "A", // Expression evaluation result
matchedCase: "A", // Matched case value
matchedPort: "gradeA" // Matched port name
}
}

Usage Examples

Example 1: Grade Evaluation System

{
"nodes": {
"score-processor": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "const student = { name: 'Alice', score: 95, subject: 'Math' }; return student;"
}
},
"grade-switch": {
"type": "control",
"config": {
"identifier": "switch"
}
},
"excellent-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'excellent', message: `Congratulations ${parameters.name}! Excellent score (${parameters.score} points)`, grade: 'A' };"
}
},
"good-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'good', message: `${parameters.name} scored well (${parameters.score} points)`, grade: 'B' };"
}
},
"pass-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'pass', message: `${parameters.name} passed (${parameters.score} points)`, grade: 'C' };"
}
},
"fail-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'fail', message: `${parameters.name} did not pass (${parameters.score} points)`, grade: 'D' };"
}
}
},
"edges": [
{
"source": "score-processor",
"target": "grade-switch",
"sourcePort": "result",
"targetPort": "data"
},
{
"source": "grade-switch",
"target": "excellent-handler",
"sourcePort": "gradeA",
"targetPort": "parameters"
},
{
"source": "grade-switch",
"target": "good-handler",
"sourcePort": "gradeB",
"targetPort": "parameters"
},
{
"source": "grade-switch",
"target": "pass-handler",
"sourcePort": "gradeC",
"targetPort": "parameters"
},
{
"source": "grade-switch",
"target": "fail-handler",
"sourcePort": "default",
"targetPort": "parameters"
}
],
"inputs": {
"grade-switch": {
"expression": "data.score >= 90 ? 'A' : data.score >= 80 ? 'B' : data.score >= 60 ? 'C' : 'D'",
"cases": [
{ "value": "A", "port": "gradeA" },
{ "value": "B", "port": "gradeB" },
{ "value": "C", "port": "gradeC" }
],
"defaultCase": { "port": "default" }
}
}
}

Example 2: Customer Tier Service Routing

{
"nodes": {
"customer-analyzer": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "const customer = { id: 'C001', name: 'John', level: 'DIAMOND', region: 'CN', spending: 50000 }; return customer;"
}
},
"service-router": {
"type": "control",
"config": {
"identifier": "switch"
}
},
"vip-service": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'premium_service', message: `Dear ${parameters.name}, you enjoy exclusive VIP service`, level: parameters.level, benefits: ['Dedicated support', 'Priority handling', 'Special discounts'] };"
}
},
"standard-service": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'standard_service', message: `Dear ${parameters.name}, thank you for your support`, level: parameters.level, benefits: ['Standard service'] };"
}
},
"basic-service": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'basic_service', message: `${parameters.name}, welcome to our service` };"
}
}
},
"edges": [
{
"source": "customer-analyzer",
"target": "service-router",
"sourcePort": "result",
"targetPort": "data"
},
{
"source": "service-router",
"target": "vip-service",
"sourcePort": "premium",
"targetPort": "parameters"
},
{
"source": "service-router",
"target": "standard-service",
"sourcePort": "standard",
"targetPort": "parameters"
},
{
"source": "service-router",
"target": "basic-service",
"sourcePort": "default",
"targetPort": "parameters"
}
],
"inputs": {
"service-router": {
"expression": "data.level",
"cases": [
{ "value": ["DIAMOND", "PLATINUM", "GOLD"], "port": "premium" },
{ "value": ["SILVER", "BRONZE"], "port": "standard" }
],
"defaultCase": { "port": "default" }
}
}
}

Example 3: Order Processing Dispatch

{
"nodes": {
"order-classifier": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "const order = { id: 'O001', amount: 1500, type: 'URGENT', priority: 'HIGH', customer: { vip: true } }; return order;"
}
},
"order-switch": {
"type": "control",
"config": {
"identifier": "switch"
}
},
"vip-order-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'vip_large_order', message: `VIP large order ${parameters.id} prioritized`, amount: parameters.amount, fast_track: true };"
}
},
"urgent-order-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'urgent_order', message: `Urgent order ${parameters.id} expedited`, priority: parameters.priority };"
}
},
"normal-order-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { type: 'normal_order', message: `Order ${parameters.id} processed normally` };"
}
}
},
"edges": [
{
"source": "order-classifier",
"target": "order-switch",
"sourcePort": "result",
"targetPort": "data"
},
{
"source": "order-switch",
"target": "vip-order-handler",
"sourcePort": "vipLarge",
"targetPort": "parameters"
},
{
"source": "order-switch",
"target": "urgent-order-handler",
"sourcePort": "urgent",
"targetPort": "parameters"
},
{
"source": "order-switch",
"target": "normal-order-handler",
"sourcePort": "normal",
"targetPort": "parameters"
}
],
"inputs": {
"order-switch": {
"expression": "data.amount > 1000 && data.customer.vip ? 'VIP_LARGE' : data.type === 'URGENT' ? 'URGENT' : 'NORMAL'",
"cases": [
{ "value": "VIP_LARGE", "port": "vipLarge" },
{ "value": "URGENT", "port": "urgent" },
{ "value": "NORMAL", "port": "normal" }
]
}
}
}

Example 4: State Machine Processing

{
"nodes": {
"task-monitor": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "const task = { id: 'task-001', status: 'pending', priority: 'high' }; return task;"
}
},
"status-router": {
"type": "control",
"config": {
"identifier": "switch"
}
},
"pending-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'pending_handled', message: `Task ${parameters.id} awaiting processing`, nextStatus: 'running' };"
}
},
"running-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'running_handled', message: `Task ${parameters.id} is executing`, progress: 50 };"
}
},
"completed-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'completed_handled', message: `Task ${parameters.id} has been completed`, completedAt: new Date().toISOString() };"
}
},
"error-handler": {
"type": "operator",
"config": {
"operator": "jsexecutor",
"code": "return { result: 'error_handled', message: `Task ${parameters.id} has an abnormal status`, needsReview: true };"
}
}
},
"edges": [
{
"source": "task-monitor",
"target": "status-router",
"sourcePort": "result",
"targetPort": "data"
},
{
"source": "status-router",
"target": "pending-handler",
"sourcePort": "pending",
"targetPort": "parameters"
},
{
"source": "status-router",
"target": "running-handler",
"sourcePort": "running",
"targetPort": "parameters"
},
{
"source": "status-router",
"target": "completed-handler",
"sourcePort": "completed",
"targetPort": "parameters"
},
{
"source": "status-router",
"target": "error-handler",
"sourcePort": "default",
"targetPort": "parameters"
}
],
"inputs": {
"status-router": {
"expression": "data.status",
"cases": [
{ "value": "pending", "port": "pending" },
{ "value": "running", "port": "running" },
{ "value": "completed", "port": "completed" }
],
"defaultCase": { "port": "default" }
}
}
}

Error Handling

Fallback Mechanism on Expression Evaluation Failure

// 1. First attempts to evaluate the expression using ConditionEvaluator
// 2. If that fails, attempts to use the expression as a property name to retrieve a value from inputData
// 3. Finally falls back to using the expression itself as the value

Handling When No Branch Matches

// If no case matches and there is no defaultCase, returns null and no branch is executed
if (!matchedPort) {
console.log('No matching branch to execute');
return null;
}

Best Practices

1. Expression Design Recommendations

// ✅ Recommended: Clear logical structure
"data.score >= 90 ? 'A' : data.score >= 80 ? 'B' : 'C'"

// ✅ Recommended: Combining multiple conditions
"data.amount > 1000 && data.customer.vip"

// ✅ Recommended: Simple property access
"data.status"
"data.user.level"

2. Branch Design Patterns

// Tiered processing pattern
{
"cases": [
{ "value": ["LEVEL_1", "LEVEL_2"], "port": "highLevel" },
{ "value": ["LEVEL_3", "LEVEL_4"], "port": "midLevel" },
{ "value": ["LEVEL_5"], "port": "lowLevel" }
],
"defaultCase": { "port": "defaultLevel" }
}

// State machine pattern
{
"cases": [
{ "value": "INIT", "port": "initialize" },
{ "value": "PROCESSING", "port": "process" },
{ "value": "COMPLETE", "port": "finalize" }
],
"defaultCase": { "port": "error" }
}

3. Debugging Tips

// Access Switch decision information within the sub-workflow
const processor = `
const switchResult = context['switch-1']._switch_result;
console.log('Switch decision info:', {
expression: switchResult.expression,
value: switchResult.expressionValue,
matchedCase: switchResult.matchedCase,
port: switchResult.matchedPort
});

return {
processed: parameters,
decision: switchResult
};
`;

4. Performance Optimization

// Place the most frequently matched cases first
{
"cases": [
{ "value": "COMMON_STATUS", "port": "commonHandler" }, // 90% of cases
{ "value": "RARE_STATUS", "port": "rareHandler" }, // 10% of cases
{ "value": "VERY_RARE", "port": "specialHandler" } // 1% of cases
]
}
Important Note

The Switch node is a pure control node. After selecting an execution path based on the condition, it halts subsequent execution of the main workflow. All business logic is completed within the selected branch sub-workflow.