Bonnard Docs
ModelingCubes

Measures

Define metrics and aggregations for analytical queries.

Overview

Measures are the quantitative values in your data model — counts, sums, averages, and other aggregations. They answer questions like "how many?", "how much?", and "what's the average?".

Example

measures:
  - name: count
    type: count
    description: Total number of orders

  - name: total_revenue
    type: sum
    sql: amount
    description: Sum of order amounts in dollars

  - name: average_order_value
    type: number
    sql: "\{total_revenue\} / NULLIF(\{count\}, 0)"
    description: Average revenue per order

  - name: completed_orders
    type: count
    filters:
      - sql: "\{CUBE\}.status = 'completed'"
    description: Orders with status completed

Required Properties

PropertyDescription
nameUnique identifier in snake_case
typeAggregation type (count, sum, avg, etc.)

Optional Properties

PropertyDescription
sqlSQL expression (required for most types)
filtersConditions for filtered aggregations
titleHuman-readable display name
descriptionDocumentation for consumers
formatOutput format (percent, currency, etc.)
publicWhether exposed in API (default: true)
rolling_windowRolling aggregation settings

Measure Types

Aggregation Types

# Count rows
- name: count
  type: count

# Count distinct values
- name: unique_users
  type: count_distinct
  sql: user_id

# Sum values
- name: total_revenue
  type: sum
  sql: amount

# Average values
- name: average_price
  type: avg
  sql: price

# Min/Max values
- name: first_order
  type: min
  sql: created_at

- name: last_order
  type: max
  sql: created_at

Calculated Types

# Calculated number (from other measures)
- name: average_order_value
  type: number
  sql: "\{total_revenue\} / NULLIF(\{count\}, 0)"

# Boolean result
- name: has_orders
  type: boolean
  sql: "\{count\} > 0"

Filtered Measures

Add conditions to only count/sum matching rows:

- name: completed_orders
  type: count
  filters:
    - sql: "\{CUBE\}.status = 'completed'"

- name: revenue_this_year
  type: sum
  sql: amount
  filters:
    - sql: "YEAR(\{CUBE\}.created_at) = YEAR(CURRENT_DATE)"

Calculated Measures

Reference other measures to build derived metrics:

- name: total_orders
  type: count

- name: completed_orders
  type: count
  filters:
    - sql: "\{CUBE\}.status = 'completed'"

- name: completion_rate
  type: number
  sql: "100.0 * \{completed_orders\} / NULLIF(\{total_orders\}, 0)"
  format: percent

Rolling Windows

Calculate metrics over time windows:

- name: rolling_7_day_revenue
  type: sum
  sql: amount
  rolling_window:
    trailing: 7 day

Best Practices

  1. Start with count — every cube should have a basic count
  2. Use descriptive namestotal_revenue not sum1
  3. Handle division by zero — always use NULLIF(x, 0)
  4. Add formats — help consumers interpret values
  5. Document complex measures — explain business logic

See Also

  • cubes.measures.types
  • cubes.measures.filters
  • cubes.measures.calculated
  • cubes.measures.rolling