-
Notifications
You must be signed in to change notification settings - Fork 0
PostgreSQL Ingress
The PostgreSQL ingress automatically syncs data from a PostgreSQL table to a Bright search index.
- Two sync modes: Polling (interval-based) and LISTEN/NOTIFY (real-time)
- Automatic schema setup: Creates required tracking tables and triggers
- Hard delete support: Tracks deleted rows via trigger
- Offline recovery: Catches up on changes after service restarts
curl -X POST "http://localhost:3000/indexes?id=products"curl -X POST "http://localhost:3000/indexes/products/ingresses" \
-H "Content-Type: application/json" \
-d '{
"id": "pg-products",
"type": "postgres",
"config": {
"dsn": "postgres://user:password@localhost:5432/mydb",
"table": "products",
"primary_key": "id",
"updated_at_column": "updated_at"
}
}'curl "http://localhost:3000/indexes/products/ingresses/pg-products"| Field | Type | Required | Default | Description |
|---|---|---|---|---|
dsn |
string | Yes | - | PostgreSQL connection string |
table |
string | Yes | - | Table name to sync |
schema |
string | No | public |
PostgreSQL schema |
primary_key |
string | No | id |
Primary key column |
columns |
string[] | No | * |
Columns to sync (empty = all) |
column_mapping |
object | No | - | Rename columns: {"db_col": "doc_field"}
|
updated_at_column |
string | No | updated_at |
Timestamp column for change detection |
where_clause |
string | No | - | Filter rows: active = true
|
sync_mode |
string | No | polling |
polling or listen
|
poll_interval |
string | No | 30s |
Polling interval (e.g., 10s, 1m) |
batch_size |
int | No | 1000 |
Documents per batch |
auto_triggers |
bool | No | true |
Auto-create PostgreSQL triggers |
{
"id": "pg-products",
"type": "postgres",
"config": {
"dsn": "postgres://user:password@localhost:5432/mydb",
"table": "products",
"schema": "public",
"primary_key": "id",
"columns": ["id", "name", "description", "price", "category"],
"column_mapping": {
"product_name": "name"
},
"updated_at_column": "updated_at",
"where_clause": "active = true AND deleted_at IS NULL",
"sync_mode": "polling",
"poll_interval": "30s",
"batch_size": 1000,
"auto_triggers": true
}
}Uses the updated_at column to detect changes. Bright queries for rows where updated_at > last_sync_time at regular intervals.
Requirements:
- Table must have an
updated_attimestamp column - Column must be updated on every INSERT and UPDATE
Pros:
- Simple setup
- Works with any PostgreSQL version
- No special permissions needed
Cons:
- Changes are not immediate (depends on poll interval)
Uses PostgreSQL's LISTEN/NOTIFY for near real-time updates. Bright creates triggers that send notifications on INSERT, UPDATE, and DELETE.
{
"config": {
"sync_mode": "listen",
"auto_triggers": true
}
}Requirements:
- PostgreSQL 9.0+
- Permission to create triggers (if
auto_triggers: true)
Pros:
- Near real-time sync
- Lower database load than polling
Cons:
- Requires trigger creation permissions
- Initial sync still uses polling
When the ingress starts, it creates these tables in your PostgreSQL database:
Stores sync state (last sync time, progress).
CREATE TABLE IF NOT EXISTS __bright_synchronization (
table_name VARCHAR(255) PRIMARY KEY,
last_sync_at TIMESTAMPTZ,
last_id TEXT,
full_sync_complete BOOLEAN DEFAULT FALSE,
updated_at TIMESTAMPTZ DEFAULT NOW()
);Tracks hard deletes via trigger.
CREATE TABLE IF NOT EXISTS __bright_synchronization_deletes (
id SERIAL PRIMARY KEY,
source_table VARCHAR(255) NOT NULL,
deleted_id TEXT NOT NULL,
deleted_at TIMESTAMPTZ DEFAULT NOW()
);When auto_triggers: true, Bright creates:
Captures deleted row IDs for sync:
CREATE TRIGGER __bright_delete_trigger_<table>
AFTER DELETE ON <table>
FOR EACH ROW EXECUTE FUNCTION __bright_track_deletes_<table>();Sends notifications on changes:
CREATE TRIGGER __bright_notify_trigger_<table>
AFTER INSERT OR UPDATE OR DELETE ON <table>
FOR EACH ROW EXECUTE FUNCTION __bright_notify_<table>();curl -X PATCH "http://localhost:3000/indexes/products/ingresses/pg-products" \
-H "Content-Type: application/json" \
-d '{"state": "paused"}'curl -X PATCH "http://localhost:3000/indexes/products/ingresses/pg-products" \
-H "Content-Type: application/json" \
-d '{"state": "running"}'Clears sync state and reimports all data:
curl -X PATCH "http://localhost:3000/indexes/products/ingresses/pg-products" \
-H "Content-Type: application/json" \
-d '{"state": "resyncing"}'curl -X DELETE "http://localhost:3000/indexes/products/ingresses/pg-products"When Bright restarts after being offline:
- Loads
last_sync_atfrom__bright_synchronizationtable - Queries all rows where
updated_at > last_sync_at - Queries
__bright_synchronization_deletesfor missed deletes - Processes all changes before resuming normal sync
This ensures no data is lost during service interruptions.
curl "http://localhost:3000/indexes/products/ingresses/pg-products"Look at the statistics field:
-
last_error: Most recent error message -
error_count: Total errors encountered -
full_sync_complete: Whether initial sync finished -
documents_synced: Total documents synced
| Issue | Cause | Solution |
|---|---|---|
connection refused |
Wrong DSN or PostgreSQL not running | Check DSN and PostgreSQL status |
permission denied |
User lacks table access | Grant SELECT on table |
trigger creation failed |
User lacks CREATE TRIGGER | Grant permission or set auto_triggers: false
|
| Documents not updating |
updated_at not being set |
Ensure column updates on every change |
| Deletes not syncing | Trigger not created | Check auto_triggers or create manually |