Computed Field Usage
Computed fields add derived fields to a dataset. They can calculate values directly with an expression, or define a field in the dataset and let a chart binding Studio script write values into it.
Common scenarios:
| Scenario | Description |
|---|---|
| Row-level calculation | Calculate amount, duration, status, or labels from the current record or joined records |
| Shared business logic | Keep repeated calculation rules in the dataset so charts can reuse the same field |
| External metric enrichment | Query Soln aggregated chart data first, then use a script to add metrics from third-party systems, member directory, approval data, or another service |
| Chart post-processing | Calculate targets, completion rates, forecasts, or warning values from aggregated chart data |
Usage Flow
Computed fields are configured in two places:
- Add the computed field in Datasets, and choose its name, data type, and value source
- Configure the field role and aggregation in Fields And Metadata
- Use the computed field in chart field slots
- If the value source is Studio Script, configure a chart Binding Script, then set match fields and assignments
- Click Run Script, check the preview, and save the chart
Expression fields are calculated during dataset preview and chart query. Script-backed fields only define the field structure in the dataset; their values are written by the chart binding script after the chart query returns aggregated data.
Add A Computed Field In A Dataset
In the dataset configuration page:
- Select Dataset Properties
- Click the Custom Column icon in the middle panel
- Enter the Field Name
- Choose the Data Type
- Choose the Value Source
- Configure the expression, or save the field as a script-backed field
- Save the computed field
| Setting | Description |
|---|---|
| Field Name | Display name used in charts. Use a business-friendly name |
| Data Type | Result type. Supported types include string, number, date, datetime, and boolean |
| Value Source | Determines whether the value is calculated by an expression or written by a chart binding script |
After saving, the computed field appears in the dataset field list. You can continue editing its display name, role, aggregation, and enabled status in Fields And Metadata.
Value Source
Expression
Use an expression when the value can be derived from the current dataset row. It can use fields from the primary form, joined forms, and common functions. Expressions are best for fixed rules that depend on row data.
Examples:
| Scenario | Example |
|---|---|
| Amount calculation | Actual Amount = Order Amount - Discount |
| Time calculation | Handling Time = Completed At - Created At |
| Status judgment | Overdue = Due Date is earlier than today |
| Group label | Customer Tier = A/B/C by accumulated amount |
Expression fields can be checked in dataset preview. Preview the dataset before saving when possible.
Studio Script
Use a Studio script when the result cannot be calculated from a row expression alone. After choosing Studio Script, the dataset saves a script-backed computed field. Dataset preview does not calculate this value directly; chart Binding Script writes the value during chart query.
Script-backed fields are useful for:
| Scenario | Description |
|---|---|
| Third-party metrics | Query targets, budgets, exchange rates, inventory, ad spend, or other external values by chart category |
| Soln data enrichment | Use Studio SDK to query form records, members, departments, organizations, approvals, or IAM data |
| Multi-step rules | Use a script for multiple queries, branches, mapping tables, weights, or algorithms |
| Aggregated calculation | Calculate completion rate, target gap, or forecast after the chart has already grouped by region, month, or owner |
| Metric card value | Return one global value, such as target amount, external balance, or real-time exchange rate |
Prefer expressions when the calculation only depends on current-row fields. Use Studio scripts when the calculation depends on aggregated chart data, another system, or complex runtime logic.
Role And Aggregation
After saving a computed field, configure its role in Fields And Metadata.
| Role | Usage |
|---|---|
| Dimension | Categories, groups, axes, colors, or filters |
| Measure | Numeric statistics, axes, size, metric cards, or targets |
Script-backed computed fields are usually measures, and their data type should be number. Chart binding scripts currently write values only into numeric computed measures.
Aggregation controls how multiple script result rows are merged when they match the same chart point:
| Aggregation | Script Binding Rule |
|---|---|
| None | Allows only one result. Multiple matched results cause a duplicate-result error |
| Sum | Adds matched values |
| Average | Averages matched values |
| Max | Uses the largest matched value |
| Min | Uses the smallest matched value |
| Count | Counts matched values that can be converted to numbers |
| Distinct Count | Counts distinct matched numeric values |
None is only available for script-backed computed fields. It is useful when each chart point must match exactly one script result. Regular fields and expression fields do not use None as an aggregation.
Bind A Script In A Chart
When a chart uses a script-backed computed field, configure Binding Script in the chart editor.
Steps:
- Open the chart editor
- Put the script-backed computed field into a measure slot, such as Y-axis measure, metric card measure, or target measure
- Open Binding Script on the left
- Select a Studio script
- Configure Match Fields when needed
- In Assignments, choose the computed field and enter the script result field
- Click Run Script
- Check the preview and save the chart
Execution order:
- The chart queries the Soln dataset using dimensions, measures, filters, and base-record limits
- The aggregated query result is passed to the Studio script as
chartData - The Studio script returns an array or
{ rows: [...] } - The system matches script rows to chart points
- The system writes script result fields into the mapped script-backed computed fields
- The chart preview renders with the updated data
Script Payload
Binding scripts are Studio scripts. The entry function follows the same pattern as the Soln SDK documentation:
export default async function main(
_payload: StudioScriptRuntimeContextPayload,
_context: StudioScriptContext
) {
return { rows: [] };
}
Chart binding scripts always receive soln.runtime-context/v1. Dataset identity is in payload.source, while query options and chart data are in payload.input:
| Path | Description |
|---|---|
payload.source.datasetId | Dataset ID used by the chart |
payload.source.dimensions | Dataset field keys used as chart dimensions |
payload.source.measures | Dataset field keys used as chart measures |
payload.input.condition | Current chart filter condition |
payload.input.timeGrain | Time grain, such as day, week, or month |
payload.input.baseRecordTimeField | Time field used for base-record selection, usually updatedAt or createdAt |
payload.input.chartData | Aggregated chart data, including categories, field metadata, series, and rows |
Common chartData shape:
type BindingChartData = {
categories: string[];
dimensions: Array<{
key: string;
name: string;
apiName: string;
dataType: string;
}>;
measures: Array<{
key: string;
name: string;
apiName: string;
dataType: string;
aggregationType: string;
valueSource: string | null;
}>;
series: Array<{
fieldKey: string;
fieldName: string;
aggregationType: string;
groupFieldKey?: string | null;
groupValue?: string | null;
data: Array<number | null>;
}>;
rows: Array<Record<string, unknown>>;
};
chartData.rows is the most useful part for scripts. Each row represents one chart point or one category-and-group combination, and includes these system fields:
| Field | Description |
|---|---|
__rowIndex | Row index of the chart point. Use it when returning values by row |
__categoryIndex | Position of the current category in categories |
__category | Current category name |
Rows also include the current chart dimension and measure fields. Keys use dataset field keys.
Script Return Format
Return rows from the script. These formats are supported:
return [
{ __rowIndex: 0, targetAmount: 1000 },
{ __rowIndex: 1, targetAmount: 2000 },
];
return {
rows: [
{ province: 'Guangdong', targetAmount: 1000 },
{ province: 'Zhejiang', targetAmount: 2000 },
],
};
return {
data: [
{ month: '2026-01', targetAmount: 5000 },
],
};
When returning an object, the row array can be named rows, items, or data. Each row should be a plain object.
Match Fields And Assignments
Match Fields decide which chart point receives each script result row.
| Setting | Description |
|---|---|
| Dataset Field | Field from the current chart data, such as province, month, or owner |
| Script Result Field | Field in the script result row, such as province, month, or ownerName |
When match fields are configured, the system compares values from chartData.rows with values from returned script rows. Only matched rows write values back to chart points.
Assignments decide which script result field writes into which computed field.
| Setting | Description |
|---|---|
| Computed Field | Numeric computed measure whose value source is Studio Script |
| Script Result Field | Returned field to write, such as targetAmount, budget, or rate |
If assignments are not configured, the system tries to read a same-name value using the computed field key or API Name. Explicit assignments are recommended because they make the chart configuration easier to understand.
Single Result Without Match Fields
If no match fields are configured and the script returns exactly one row, the system writes that row to chart point 0 by default. This is useful for metric cards or single-row totals.
Example:
export default async function main(_payload: StudioScriptRuntimeContextPayload) {
return {
rows: [
{ targetAmount: 100000 },
],
};
}
If the chart has multiple categories, configure match fields or return __rowIndex explicitly.
Example: Calculate By Chart Row
This example reads chartData.rows and calculates a target value from each chart point's current sales value.
type BindingInput = {
chartData: {
rows: Array<Record<string, unknown>>;
};
};
export default async function main(payload: StudioScriptRuntimeContextPayload) {
const input = payload.input as BindingInput;
return {
rows: input.chartData.rows.map((row) => {
const sales = Number(row['t0.amount'] || 0);
return {
__rowIndex: row.__rowIndex,
targetAmount: Math.round(sales * 1.2),
};
}),
};
}
Chart configuration:
| Setting | Value |
|---|---|
| Assignments | Computed field: Target Amount; script result field: targetAmount |
| Match Fields | Not needed, because the script returns __rowIndex |
Example: Match External Results By Province
This example fits a chart grouped by province. The script returns one target amount per province.
type BindingInput = {
chartData: {
rows: Array<Record<string, unknown>>;
};
};
export default async function main(payload: StudioScriptRuntimeContextPayload) {
const input = payload.input as BindingInput;
const provinces = input.chartData.rows.map((row) => String(row['t0.province'] || ''));
const targetByProvince: Record<string, number> = {
Guangdong: 120000,
Zhejiang: 90000,
Jiangsu: 85000,
};
return {
rows: provinces.map((province) => ({
province,
targetAmount: targetByProvince[province] || 0,
})),
};
}
Chart configuration:
| Setting | Value |
|---|---|
| Match Fields | Dataset field: Province; script result field: province |
| Assignments | Computed field: Target Amount; script result field: targetAmount |
If the script returns data at a finer grain than the chart, such as multiple city rows for one province, the system uses the computed field's aggregation to merge rows. For target amount, Sum is usually the right aggregation.
Example: Query Soln Data With SDK
Scripts can use studioScriptContext to call Soln SDK. See Soln SDK for detailed capabilities.
The example below reads province targets from a target form and writes them back to the chart.
type BindingInput = {
chartData: {
rows: Array<Record<string, unknown>>;
};
};
export default async function main(
payload: StudioScriptRuntimeContextPayload,
context: StudioScriptContext
) {
const input = payload.input as BindingInput;
const provinceNames = Array.from(
new Set(input.chartData.rows.map((row) => String(row['t0.province'] || '')))
).filter(Boolean);
const targetRecords = await context.form.list({
formApiName: 'sales_targets',
limit: 100,
condition: {
logic: 'and',
children: [
{
field: 'province',
operator: 'in',
value: provinceNames,
},
],
},
});
return {
rows: targetRecords.items.map((record) => ({
province: record.data.province,
targetAmount: record.data.targetAmount,
})),
};
}
Configure province as the match field, then assign targetAmount to the target amount computed field.
Example: Call Third-Party Data
If the current Studio script runtime allows external requests, use the runtime-supported HTTP capability to call third-party systems. A common pattern is to read categories from chartData.rows, then request external data in batch.
type BindingInput = {
chartData: {
rows: Array<Record<string, unknown>>;
};
};
export default async function main(
payload: StudioScriptRuntimeContextPayload,
context: StudioScriptContext
) {
const input = payload.input as BindingInput;
const months = input.chartData.rows.map((row) => String(row['t0.month'] || ''));
const response = await context.http.requestJson({
url: 'https://example.com/api/monthly-targets',
method: 'POST',
json: { months },
});
if (!response.ok) {
throw new Error('MONTHLY_TARGET_REQUEST_FAILED');
}
const result = response.data as {
rows: Array<{ month: string; targetAmount: number }>;
};
return {
rows: result.rows,
};
}
When an external request fails, either throw an error so chart preview shows a failure, or use try/catch to return empty rows or defaults. See the script error handling section in Soln SDK.
Troubleshooting
The Script Field Has No Value In Dataset Preview
This is expected. Script-backed computed fields are written by chart binding scripts. Dataset preview does not run chart binding scripts. Use Run Script in the chart editor to preview values.
The Script Field Has No Value In The Chart
Check these items:
- The chart uses the dataset that contains the script-backed computed field
- The computed field is numeric and is placed into a measure slot
- A Studio script is selected in Binding Script
- The assignment result field matches the field returned by the script
- Match fields can find the same values in
chartData.rowsand returned script rows - The script returns an array,
{ rows: [...] },{ items: [...] }, or{ data: [...] }
Multiple Script Results Cause An Error
When aggregation is None, each chart point can match only one script result. If one chart point should merge multiple rows, change the computed field aggregation to Sum, Average, Max, Min, Count, or Distinct Count.
Expression Or Studio Script?
Use this rule of thumb:
| Condition | Recommendation |
|---|---|
| Only current-row fields are needed | Use an expression |
| Primary and joined fields are enough for a fixed calculation | Use an expression |
| Aggregated chart categories, groups, or measures are needed | Use a Studio script |
| Other Soln records, members, departments, approvals, or IAM data are needed | Use a Studio script and Soln SDK |
| Third-party system data is needed | Use a Studio script |
Best Practices
- Use business-friendly field names, such as Target Amount, Completion Rate, or External Inventory
- Choose number as the data type for script-backed measures
- Prefer expressions when they can solve the calculation cleanly
- Keep returned script field names stable, such as
targetAmount,budgetAmount, orcompletionRate - Configure assignments explicitly in charts instead of relying on same-name matching
- Set the computed field aggregation before returning multiple rows for one chart point
- Query in batches inside scripts instead of making one request per chart point
- Handle external request failures, empty values, and timeouts so chart preview remains understandable