Skip to main content
This feature is experimental and may change in future releases.

Overview

The PostgreSQL aggregation sink enables real-time aggregations directly in PostgreSQL using database triggers. Data flows into a landing table, and a trigger function automatically maintains aggregated values in a separate aggregation table. This is useful for:
  • Account balances
  • Liquidity pools
  • Running totals
  • Trade statistics
  • Event counts by category

How it works

  1. Landing table: Stores raw records in append-only mode with a composite primary key (primary_key + _gs_op)
  2. Aggregation table: Stores aggregated results, updated incrementally by a PostgreSQL trigger
  3. Trigger function: Automatically generated and executed on each insert to update aggregations

Configuration

Parameters

string
required
Must be postgres_aggregate
string
required
The transform or source to read data from
string
required
PostgreSQL schema name (e.g., public, analytics)
string
required
Table name for raw records. Created automatically if it doesn’t exist.
string
required
Table name for aggregated results. Created automatically if it doesn’t exist.
string
required
Column to use for deduplication in the landing table
string
required
Name of a Goldsky secret holding the PostgreSQL connection details. Uses the same format as the PostgreSQL sink.
object
Columns to group by. Omit for global aggregations.
object
required
Aggregation columns. At least one is required.
integer
Maximum number of rows to accumulate before flushing to the landing table. Falls back to the engine default when unset.
string
Maximum time to wait before flushing a partial batch, parsed as a humantime duration (for example, "500ms", "1s", "2s"). Falls back to the engine default when unset.

Group by columns

Each group by column can have:
string
Source column name. Defaults to the key name if omitted.
string
PostgreSQL type override (e.g., varchar(100), text)

Aggregate columns

Each aggregate column requires:
string
required
Aggregation function: sum, count, avg, min, or max
string
Source column name. Defaults to the key name if omitted. Not required for count.
string
PostgreSQL type override (e.g., numeric(30,5))

Supported aggregation functions

The trigger inspects each record’s _gs_op column (i = insert, u = update, d = delete) to decide how to contribute the value to the running aggregate.
sum and avg do not support updates: These functions cannot correctly handle updates because they would need the old value to compute the delta. The trigger treats an update like an insert and adds the new value on top of the previous aggregate, double-counting the row. Use only with insert/delete streams.min and max do not support deletes or updates: These functions cannot retract values without rescanning the entire landing table. Use only with insert-only streams.

Deduplication

The landing table uses append-only mode with a composite primary key (primary_key + _gs_op). This enables:
  • Deduplication within checkpoint window: Duplicate records (same primary key and operation type) arriving within the same checkpoint epoch are deduplicated via upsert. Records with the same key but different operations (e.g., insert and delete) are stored separately.
  • Checkpoint-based truncation: The landing table includes a _gs_checkpoint_epoch column. When a checkpoint is finalized, data from previous epochs is deleted, keeping the landing table small.
Deduplication only works within the checkpoint window. Records arriving in different checkpoint epochs are not deduplicated. See Delivery guarantees for how checkpoint epochs work and where duplicates can occur.

Examples

Multiple aggregations with type override

Global aggregation (no group by)

For aggregations across all records without grouping:
When no group_by is defined, a sentinel key column is added automatically to the aggregation table.

Column renaming

Use from to map source columns to different output names:

Generated SQL

The sink automatically creates the trigger function and trigger. Here’s an example of the generated SQL for a balance aggregation:

Complete pipeline example

Best practices

  • Use count for counting events (supports all operations)
  • Use sum for totals when you have insert/delete streams
  • Use min/max only for insert-only streams
  • Avoid avg with updates; use sum and count separately if needed
For financial data, specify explicit numeric precision:
The landing table is automatically truncated after checkpoint finalization, but monitor its size during high-throughput periods.
Choose a unique, stable identifier for the primary_key to ensure proper deduplication: