Document pipelines
Filter, group, aggregate, sort and reshape documents in one request — like Firestore pipelines — run inside your project's database as the caller.
A pipeline is an ordered list of stages over a collection (or a collection group). Each stage takes the previous stage's output: filter with where, group and total with aggregate, then sort, page and pick fields. The whole pipeline compiles to one SQL statement and runs in your project's Postgres as the caller, so collection rules and row policies apply to every document it reads.
| Stage | Example | What it does |
|---|---|---|
where | ["status", "==", "paid"] | Filters, with the same operators and or / and groups as queries. After an aggregate it filters the groups by their aliases. |
aggregate | {"accumulators": [{"op": "sum", "field": "amount", "alias": "total"}], "groups": ["country"]} | One row per group (or one row for everything). Ops: count, count_distinct, sum, avg, min, max. |
distinct | ["country", "city"] | One row per distinct combination. |
sort | [["total", "desc"], "name"] | Orders the rows; carried through later stages. |
offset / limit | 20 / 10 | Skip / keep rows (in the current sort order). |
select | ["name", {"field": "address.city", "as": "city"}] | Keeps only these fields. A nested field is named by its last segment unless you give as. |
remove_fields | ["secret", "meta.raw"] | Drops fields. |
sample | 50 | That many rows at random. |
curl -s -X POST $URL/api/v1/data/doc/_pipeline/orders -H "Authorization: Bearer $TOKEN" -d '{
"stages": [
{"where": [["status", "==", "paid"]]},
{"aggregate": {"accumulators": [{"op": "sum", "field": "amount", "alias": "total"},
{"op": "count", "alias": "orders"}], "groups": ["country"]}},
{"where": [["total", ">", 1000]]},
{"sort": [["total", "desc"]]},
{"limit": 5}
]}'
# → {"results": [{"data": {"country": "in", "total": 18250, "orders": 97}}, …], "count": 5, "documents_read": 4120}#Performance and limits
- Leading
wherestages become the query's filter on the documents table, so your document indexes apply. Put the most selective filter first. - A
sortfollowed bylimitkeeps Postgres' top-N sort: only the rows it returns are fully sorted. - A pipeline that doesn't start (after its filters) with a
limitreads at most your plan's *documents read per pipeline*. If it would read more it is refused, never answered from part of the data — add awhereor alimit. - sum, avg, min and max use numbers (min/max fall back to strings when a group has no numbers); other values are skipped, like Firestore.
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Document pipeline queries (where, aggregate, sort, limit, select) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Stages per document pipeline | 5 | 10 | 20 | 30 | 50 |
| Documents one pipeline may read | 10,000 | 100,000 | 500,000 | 1,000,000 | 5,000,000 |
| Documents one collection scan may return | 1,000 | 5,000 | 10,000 | 25,000 | 50,000 |