GUBUS REDUCE
REDUCE aggregates data across multiple objects to produce summary values. It's one of the most powerful transforms in GUBUS, enabling totals, counts, averages, grouping, and statistical analysis.
Use REDUCE to aggregate, group, and summarize data. Supports totals, counts, averages, grouping, and more. For field preservation, see the MULTISET pattern below.
Overview
REDUCE aggregates data across multiple objects to produce summary values. Itβs one of the most powerful transforms in GUBUS, enabling totals, counts, averages, grouping, and statistical analysis.
When to use:
- Calculate total revenue, sum of payments, or any numeric aggregation
- Count items by category or status
- Find minimum or maximum values
- Group transactions by multiple fields (contragent, category, etc.)
- Concatenate strings with or without uniqueness
- Extract first/last values from ordered data
Key characteristics:
- 3 execution modes: Simple (single value), Accum (group by field), Split (positive/negative)
- 14+ reduce instructions covering numeric, statistical, string, and extraction operations
- Can persist results to side objects or replace local objects
- Supports multi-field grouping (comma-separated union_field)
- IMPORTANT: Only keeps fields involved in reduction (union_field + from_field + to_field) if only basic property is configured. Use second config with MULTISET to preserve additional fields.
How It Works
[Read objects from reduce_source]
β [Apply reduce instruction]
ββ Simple Reduce: One aggregate value across all objects
ββ Accum Reduce: Group by union_field, aggregate each group
ββ Split Reduce: Separate positive/negative results
β [Inherit all fields from match objects if second property with MULTISET is configured]
β [Store in new_target_to_persist or replace localObjs]
```json
{
"reference": "groupByContragentAndKassa",
"union_field": "contragent,kassa_type",
"from_field": "amount",
"instruction": "sum_of_floats",
"to_field": "total_amount",
"reduce_source": "local"
}
// Property 2: Preserve additional fields (SAME reference!)
{
"reference": "groupByContragentAndKassa", // β SAME!
"union_field": "contragent,kassa_type", // β SAME!
"from_field": "category,subcategory,sales_quality", // Fields to preserve
"instruction": "multiset"
}
"from_field": "amount",
"to_field": "total_revenue",
"reduce_source": "local"
}
Input: <code>[{amount: 100}, {amount: 200}, {amount: 150}]</code>
Output: <code>[{total_revenue: 450}]</code> (single object)
Use Cases:
- Total sales across all orders
- Count all transactions
- Find maximum price across products
- Average order value
Second way to achieve this result is to use GATHER_FROM_ALL_OBJECTS that will persist result in context_variables. Check out its documentation for more details.
Mode 2: Accum Reduce (Group By Field)
Service Method: executeAccumReduceWithRule
Groups by union_field, aggregates each group separately. Supports multi-field grouping (comma-separated).
Single Field Grouping:
{
"reference": "sumByCategory",
"instruction": "sum_of_floats",
"union_field": "category",
"from_field": "amount",
"to_field": "category_total",
"reduce_source": "local"
}
Input:
[
{ "product": "A", "category": "Electronics", "amount": 100 },
{ "product": "B", "category": "Electronics", "amount": 200 },
{ "product": "C", "category": "Furniture", "amount": 150 }
]
Output:
[
{ "category": "Electronics", "category_total": 300 },
{ "category": "Furniture", "category_total": 150 }
]
Multi-Field Grouping:
{
"reference": "groupByContragentAndKassa",
"instruction": "sum_of_floats",
"union_field": "contragent,kassa_type",
"from_field": "amount",
"to_field": "total_amount",
"reduce_source": "local",
"new_target_to_persist": "side_obj",
"new_ref_to_persist": "groupedTransactions"
}
Input:
[
{ "contragent": "ClientA", "kassa_type": "cash", "amount": 100 },
{ "contragent": "ClientA", "kassa_type": "cash", "amount": 50 },
{ "contragent": "ClientA", "kassa_type": "card", "amount": 200 },
{ "contragent": "ClientB", "kassa_type": "cash", "amount": 150 }
]
Output (in sideObjs[βgroupedTransactionsβ]):
[
{ "contragent": "ClientA", "kassa_type": "cash", "total_amount": 150 },
{ "contragent": "ClientA", "kassa_type": "card", "total_amount": 200 },
{ "contragent": "ClientB", "kassa_type": "cash", "total_amount": 150 }
]
Use Cases:
- Group sales by region and product category
- Sum payments by contragent and payment type
- Count orders by status and priority
- Average delivery time by carrier and destination
Mode 3: Split Reduce (Positive/Negative Results)
Service Methods: executeSplitReduceEquals, executeSplitReduceIncludes
Splits objects into two groups based on condition, aggregates each separately.
Split by Equals:
{
"reference": "splitByStatus",
"reduce_type": "count_split_equals_and_not",
"instruction": "count",
"from_field": "status",
"to_field": "completed_count,pending_count",
"instruction_args": "completed",
"reduce_source": "local"
}
Input: <code>[{status: "completed"}, {status: "pending"}, {status: "completed"},
{status: "completed"}]</code>
Output: <code>[{completed_count: 3}, {pending_count: 1}]</code>
Split by Includes:
{
"reference": "splitByRegion",
"reduce_type": "split_reduce_includes",
"instruction": "sum_of_ints",
"union_field": "region",
"from_field": "amount",
"to_field": "target_regions_total,other_regions_total",
"instruction_args": "East,West,South",
"reduce_source": "local"
}
Use Cases:
- Split revenue into target/non-target regions
- Separate completed vs pending counts
- Divide transactions into categories
Reduce Instructions
Numeric Aggregation
| Instruction | Purpose | from_field | Output Type |
|---|---|---|---|
| sum_of_ints | Sum integer values | Required | Integer |
| sum_of_floats | Sum float values | Required | Float |
| sum_of_floats_to_int | Sum floats, round int | Required | Integer |
| max | Find maximum value | Required | Number |
| min | Find minimum value | Required | Number |
Example (sum_of_floats):
{"instruction": "sum_of_floats", "from_field": "price", "to_field": "total_price"}
Input: <code>[{price: 10.5}, {price: 20.3}]</code> β Output: <code>[{total_price: 30.8}]</code>
Statistical Operations
| Instruction | Purpose | from_field | Notes |
|---|---|---|---|
| count | Count objects with non-empty from_field | Required | Skips empty values |
Example (count):
{"instruction": "count", "from_field": "order_id", "to_field": "order_count"}
Input: <code>[{order_id: "A"}, {order_id: ""}, {order_id: "B"}]</code> β
Output: <code>[{order_count: 2}]</code> (skips empty)
String Concatenation
| Instruction | Purpose | Uniqueness | Separator |
|---|---|---|---|
| concat | Join strings | No | None |
| concat_unique | Join unique | Yes | None |
| concat_comma | Join with comma | No | , |
| concat_unique_comma | Join unique comma | Yes | , |
| concat_hyphen | Join with hyphen | No | - |
| concat_unique_hyphen | Join unique hyphen | Yes | - |
Example (concat_unique_comma):
{"instruction": "concat_unique_comma", "from_field": "customer_name", "to_field": "all_customers"}
Input: <code>[{customer_name: "John"}, {customer_name: "Jane"}, {customer_name: "John"}]</code>
Output: <code>[{all_customers: "John, Jane"}]</code> (John appears once)
Value Extraction
| Instruction | Purpose | Behavior |
|---|---|---|
| first | Extract first | Takes value from first |
| last | Extract last | Takes value from last |
| set | Set single val | Overwrites with each |
| multiset | Set multiple | Copies multiple fields |
Example (first):
{"instruction": "first", "from_field": "created_at", "to_field": "first_created"}
Input: <code>[{created_at: "2025-01-01"}, {created_at: "2025-01-05"}]</code>
Output: <code>[{first_created: "2025-01-01"}]</code>
Example (multiset):
{"instruction": "multiset", "from_field": "name,email,phone", "to_field": "not_used"}
π MULTISET Power Feature: Field Preservation in Group Reduce
MULTISET has a CRITICAL use case that solves the field discarding problem:
When using Accum Reduce (group by), you can define TWO reduce properties with the SAME reference. Both execute in the same reduce operation:
- Property 1: Main aggregation (sum, count, max, etc.)
- Property 2: MULTISET to preserve additional fields from first object in each group
This allows you to:
- Group and aggregate data
- Preserve fields that would otherwise be discarded
- Place REDUCE anywhere in transform chain without worrying about field loss
Complete Example:
Scenario: Group transactions by contragent and kassa_type, BUT also preserve category, subcategory, and sales_quality fields that come from earlier JOIN and TRANSFORM.
Two Properties with SAME Reference:
// Property 1: Main aggregation
{
"reference": "groupByContragentAndKassa",
"union_field": "contragent,kassa_type",
"from_field": "amount",
"instruction": "sum_of_floats",
"to_field": "total_amount",
"reduce_source": "local"
}
// Property 2: Preserve additional fields (SAME reference!)
{
"reference": "groupByContragentAndKassa", // β SAME!
"union_field": "contragent,kassa_type", // β SAME!
"from_field": "category,subcategory,sales_quality", // Fields to preserve
"instruction": "multiset",
}
Input (after JOIN and TRANSFORM added fields):
[
{ "contragent": "ClientA", "kassa_type": "cash", "amount": 100, "category": "Sales",
"subcategory": "Retail", "sales_quality": "Premium" },
{ "contragent": "ClientA", "kassa_type": "cash", "amount": 50, "category": "Sales",
"subcategory": "Retail", "sales_quality": "Premium" },
{ "contragent": "ClientA", "kassa_type": "card", "amount": 200, "category": "Sales",
"subcategory": "Online", "sales_quality": "Standard" }
]
Output:
[
{
"contragent": "ClientA",
"kassa_type": "cash",
"total_amount": 150, // β Aggregated by Property 1
"category": "Sales", // β Preserved by Property 2 (MULTISET)
"subcategory": "Retail", // β Preserved by Property 2
"sales_quality": "Premium" // β Preserved by Property 2
},
{
"contragent": "ClientA",
"kassa_type": "card",
"total_amount": 200,
"category": "Sales",
"subcategory": "Online",
"sales_quality": "Standard"
}
]
No field loss β JOIN and TRANSFORM fields are preserved. REDUCE can be placed anywhere in transform chain. Clean aggregated results with context intact.
Output Behavior & Field Retention
After reduce executes, sc.localObjs contains ONLY:
- Fields in
union_field(if Accum Reduce) - Field in
to_field(aggregated result) - All other fields are DISCARDED unless preserved with MULTISET.
Common Use Cases
Use Case 1: Calculate Total Revenue
{
"reference": "totalRevenue",
"instruction": "sum_of_floats",
"from_field": "amount",
"to_field": "daily_revenue",
"reduce_source": "local"
}
Input: <code>[{amount: 100}, {amount: 250}, {amount: 175}]</code>
Output: <code>[{daily_revenue: 525}]</code>
Use Case 2: Count By Status
{
"reference": "countByStatus",
"instruction": "count",
"union_field": "status",
"from_field": "order_id",
"to_field": "status_count",
"reduce_source": "local"
}
Input: <code>[{status: "completed", order_id: "A"}, {status: "pending", order_id: "B"},
{status: "completed", order_id: "C"}]</code>
Output: <code>[{status: "completed", status_count: 2}, {status: "pending", status_count: 1}]</code>
Use Case 3: Group Sales Summary (Multi-Field)
{
"reference": "salesSummary",
"instruction": "sum_of_floats",
"union_field": "region,product_type",
"from_field": "sales",
"to_field": "total_sales",
"reduce_source": "local",
"new_target_to_persist": "side_obj",
"new_ref_to_persist": "salesSummary",
"message": "Sales summarized by region and product type"
}
Creates grouped summary objects in sideObjs[βsalesSummaryβ].
Use Case 4: Find Maximum Price Per Category
{
"reference": "maxPriceByCategory",
"instruction": "max",
"union_field": "category",
"from_field": "price",
"to_field": "max_price",
"reduce_source": "local"
}
Each category gets its maximum price.
Use Case 5: Concatenate Customer Names
{
"reference": "allCustomers",
"instruction": "concat_unique_comma",
"from_field": "customer_name",
"to_field": "customer_list",
"reduce_source": "local"
}
Input: <code>[{customer_name: "John"}, {customer_name: "Jane"}, {customer_name: "John"}]</code>
Output: <code>[{customer_list: "John, Jane"}]</code>
Summary
REDUCE aggregates data to produce summary values:
- 3 execution modes: Simple (single value), Accum (group by field), Split (positive/negative)
- 14+ instructions: sum, count, max, min, concat (with variants), first, last, set, multiset
- Multi-field grouping: Comma-separated union_field for complex categorization
- Field discarding: Only keeps fields involved in reduction
- Flexible output: Can persist to side objects or replace local objects
When to use: Financial calculations, statistical summaries, report generation, metrics aggregation, string concatenation, value extraction
When NOT to use: Field transformations (TRANSFORM), filtering (FILTER), merging (JOIN), data enrichment
Key for AI developers: Use upsertNonUniqueMultipleRuleProperties (with ruleName=βreduceβ) to configure reduce rules with proper Reducer[] structure, save_all_rules to sync changes to database, and always validate with getSchemaFlow or test execution. The tool wraps upsertToAdminSheetNonUniqueMultipleRulePropsV2WOSC method and supports dual-property patterns for rules like reduce that allow multiple properties with same reference.
Next Steps
π GUBUS SCHEMA β - Learn how schemas orchestrate workflows π GUBUS WORKFEED β - Learn about permanent data storage π β Back to Getting Started - Return to the main documentation