Listing & pagination
Sorted, limited, paginated reads with List.
List reads many rows with filtering, sorting, a limit, and pagination (either
cursor- or offset-based) — one method on every backend. It's part of the
Store interface, so the same code works on PostgreSQL, MongoDB, and
DynamoDB.
rows, err := db.List(ctx, "posts", dbswitch.ListOptions{
Filter: map[string]any{"status": "PUBLISHED"},
SortBy: "created_at",
SortDir: dbswitch.Descending,
Limit: 20,
})ListOptions
Every field is optional — the zero value is "all rows, unordered, no limit" (same as
Find).
| Field | Type | Meaning |
|---|---|---|
Filter | map[string]any | Equality conditions, ANDed (like Find's where) |
SortBy | string | Field to order by. Empty = no explicit ordering |
SortDir | SortDirection | Ascending (default) or Descending |
Limit | int | Max rows. 0 = no limit |
Offset | int | Skip N rows before returning results. 0 = no skip |
After | any | Cursor — see below |
Sorting & limiting
// Newest 10 published posts.
rows, err := db.List(ctx, "posts", dbswitch.ListOptions{
Filter: map[string]any{"status": "PUBLISHED"},
SortBy: "created_at",
SortDir: dbswitch.Descending,
Limit: 10,
})This compiles to (Postgres):
SELECT * FROM "posts" WHERE "status" = $1 ORDER BY "created_at" DESC LIMIT 10…and to an equivalent find + sort + limit on MongoDB. On DynamoDB, sorting and
filtering on anything besides "id" are emulated in memory after a Scan — see
Backends.
Offset (page-based) pagination
Set Offset to skip a fixed number of rows — the familiar page N = (N-1) * Limit model:
const pageSize = 20
page := 3
opts := dbswitch.ListOptions{
SortBy: "created_at",
SortDir: dbswitch.Descending,
Limit: pageSize,
Offset: (page - 1) * pageSize,
}
rows, err := db.List(ctx, "posts", opts)Offset makes the database (or, on DynamoDB, the in-memory emulation) walk and discard
every skipped row, so it gets slower the deeper you page. Prefer After (cursor,
below) for large or deeply-paged result sets.
Cursor pagination
Set After together with SortBy to fetch the next page: only rows past the cursor
in the sort direction are returned — SortBy > After for Ascending, SortBy < After for
Descending. Pass the SortBy value of the last row from the previous page.
opts := dbswitch.ListOptions{
SortBy: "created_at",
SortDir: dbswitch.Descending,
Limit: 20,
}
// Page 1
page, _ := db.List(ctx, "posts", opts)
// Page 2: continue after the last row of page 1
if len(page) > 0 {
opts.After = page[len(page)-1]["created_at"]
page, _ = db.List(ctx, "posts", opts)
}On PostgreSQL and MongoDB, cursor pagination is keyset-based (a WHERE sort_col <> cursor comparison), not OFFSET — so it stays fast on large tables and doesn't
skip/repeat rows when data changes between pages. Use a sort column that's unique (or
unique-enough) to avoid ties at the boundary.
After only takes effect when SortBy is also set. Filters remain equality-only — for
range filters (created_at < …) beyond the cursor, you still need your driver directly
(see Limitations).