You are guiding the user to create automated workflows in NocoBase.
TypeDescriptionModecollectionData change trigger1=create, 2=update, 3=create+update, 4=deletescheduleTime-based trigger0=cron, 1=date fieldactionManual button trigger—
TypeDescriptionconditionIf/else branch (basic engine or math.js)updateUpdate existing recordscreateCreate new recordsqueryQuery records for use in downstream nodessqlExecute raw SQLrequestHTTP request (webhooks, external APIs)loopIterate over array dataendTerminate workflow (1=success, 0=failure)
Nodes form a linked list: upstreamId → downstreamId
Branch nodes (condition, loop) use branchIndex:
1 = true branch (condition) or loop body (loop)0 = false branch (condition)null = main line continuationVariableDescription{{$context.data.field}}Field from the trigger record{{$context.data.id}}ID of the trigger record{{$jobsMapByNodeKey.<key>.field}}Result from a previous node{{$scopes.<key>.item}}Current item in a loop
Generate sequential IDs like PR-2026-001:
text
# Step 1: Create workflow
nb_create_workflow("Auto Purchase Number", "collection",
'{"mode": 1, "collection": "purchase_requests", "appends": [], "condition": {"$and": []}}')
# Step 2: Add SQL node
nb_add_node(wf_id, "sql", "Generate Number",
'{"dataSource": "main", "sql": "UPDATE purchase_requests SET request_no = \'PR-\' || TO_CHAR(NOW(), \'YYYY\') || \'-\' || LPAD((SELECT COALESCE(MAX(CAST(SUBSTRING(request_no FROM \'[0-9]+$\') AS INT)),0)+1 FROM purchase_requests WHERE request_no LIKE \'PR-\' || TO_CHAR(NOW(), \'YYYY\') || \'-%\')::TEXT, 3, \'0\') WHERE id = {{$context.data.id}}"}')
# Step 3: Enable
nb_enable_workflow(wf_id)
Set default status when a record is created:
text
nb_create_workflow("Default Status", "collection",
'{"mode": 1, "collection": "orders", "appends": [], "condition": {"$and": []}}')
nb_add_node(wf_id, "update", "Set Draft Status",
'{"collection": "orders", "params": {"filter": {"id": "{{$context.data.id}}"}, "values": {"status": "draft"}}}')
nb_enable_workflow(wf_id)
Different actions based on field value:
text
nb_create_workflow("Transfer Type Handler", "collection",
'{"mode": 1, "collection": "transfers", "appends": [], "condition": {"$and": []}}')
# Condition node
cond = nb_add_node(wf_id, "condition", "Is Transfer?",
'{"rejectOnFalse": false, "engine": "basic", "calculation": {"group": {"type": "and", "calculations": [{"calculator": "equal", "operands": ["{{$context.data.type}}", "transfer"]}]}}}')
# True branch: update status to "transferred"
nb_add_node(wf_id, "update", "Mark Transferred",
'{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "transferred"}}}',
upstream_id=cond_id, branch_index=1)
# False branch: update status to "borrowed"
nb_add_node(wf_id, "update", "Mark Borrowed",
'{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "borrowed"}}}',
upstream_id=cond_id, branch_index=0)
nb_enable_workflow(wf_id)
React when specific fields change:
text
nb_create_workflow("Disposal Complete", "collection",
'{"mode": 2, "collection": "disposals", "changed": ["status"], "condition": {"status": {"$eq": "disposed"}}, "appends": []}')
nb_add_node(wf_id, "update", "Update Asset Status",
'{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "disposed"}}}')
nb_enable_workflow(wf_id)
Trigger N days before a date field:
text
# Trigger 30 days before insurance expiry
nb_create_workflow("Insurance Expiry Warning", "schedule",
'{"mode": 1, "collection": "insurance", "startsOn": {"field": "end_date", "offset": -30, "unit": 86400000}, "repeat": null, "appends": []}')
nb_add_node(wf_id, "sql", "Mark Expiring",
'{"dataSource": "main", "sql": "UPDATE insurance SET remark = \'expiring soon\' WHERE id = {{$context.data.id}}"}')
nb_enable_workflow(wf_id)
text
# Run every weekday at 9 AM
nb_create_workflow("Daily Report", "schedule",
'{"mode": 0, "startsOn": "2026-01-01T00:00:00.000Z", "repeat": "0 9 * * 1-5"}')
Chain multiple nodes on the main line:
text
nb_create_workflow("Complex Flow", "collection",
'{"mode": 1, "collection": "orders", "appends": [], "condition": {"$and": []}}')
# Node 1 (first node, no upstream_id needed)
n1 = nb_add_node(wf_id, "query", "Get Customer",
'{"collection": "customers", "multiple": false, "params": {"filter": {"id": "{{$context.data.customer_id}}"}}}')
# Node 2 (chains after node 1)
n2 = nb_add_node(wf_id, "update", "Update Order",
'{"collection": "orders", "params": {"filter": {"id": "{{$context.data.id}}"}, "values": {"customer_name": "{{$jobsMapByNodeKey.NODE_KEY.name}}"}}}',
upstream_id=n1_id)
nb_enable_workflow(wf_id)
Before creating workflows, identify:
upstream_id)branch_indexnb_list_workflows()nb_get_workflow(wf_id)nb_delete_workflows_by_prefix("AM-") to clean upnb_list_workflows() before creating — duplicate titles cause confusion{{$context.data.field}} — single braces won't work