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
- Landing table: Stores raw records in append-only mode with a composite primary key (
primary_key+_gs_op) - Aggregation table: Stores aggregated results, updated incrementally by a PostgreSQL trigger
- Trigger function: Automatically generated and executed on each insert to update aggregations
Configuration
Parameters
string
required
Must be
postgres_aggregatestring
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 maxstring
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.
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_epochcolumn. 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:group_by is defined, a sentinel key column is added automatically to the aggregation table.
Column renaming
Usefrom 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
Choose the right aggregation function
Choose the right aggregation function
- Use
countfor counting events (supports all operations) - Use
sumfor totals when you have insert/delete streams - Use
min/maxonly for insert-only streams - Avoid
avgwith updates; usesumandcountseparately if needed
Use type overrides for precision
Use type overrides for precision
For financial data, specify explicit numeric precision:
Monitor landing table size
Monitor landing table size
The landing table is automatically truncated after checkpoint finalization, but monitor its size during high-throughput periods.
Use appropriate primary keys
Use appropriate primary keys
Choose a unique, stable identifier for the
primary_key to ensure proper deduplication: