Sorting And Pagination
Sorting and Pagination
Learn how to sort records, implement efficient pagination, and handle large datasets when working with the Tadabase REST API.
Basic Sorting
Sort by Single Field
Use the order and order_by query parameters:
GET /api/v1/data-tables/{tableId}/records?order=last_name&order_by=asc
Headers:
X-Tadabase-App-id: your_app_id
X-Tadabase-App-Key: your_app_key
X-Tadabase-App-Secret: your_app_secret
Sort Parameters
| Parameter | Description | Values |
|---|---|---|
order |
Field slug to sort by | Any field slug (e.g., "created_at", "last_name") |
order_by |
Sort direction | asc (ascending) or desc (descending) |
Common Sorting Examples
Sort by Date (Newest First)
GET /api/v1/data-tables/{tableId}/records?order=created_at&order_by=desc
Sort Alphabetically
GET /api/v1/data-tables/{tableId}/records?order=name&order_by=asc
Sort by Number (Highest First)
GET /api/v1/data-tables/{tableId}/records?order=price&order_by=desc
Multiple Field Sorting
To sort by multiple fields, use POST with JSON body:
POST /api/v1/data-tables/{tableId}/records
Content-Type: application/json
{
"sort_by": [
{
"sort": "status",
"by": "desc"
},
{
"sort": "created_at",
"by": "asc"
}
],
"limit": 50
}
This sorts by status (descending) first, then by created_at (ascending) for records with the same status.
Multiple Sort Use Cases
Group by Status, Then by Date
{
"sort_by": [
{"sort": "status", "by": "asc"},
{"sort": "due_date", "by": "asc"}
]
}
Sort by Priority and Name
{
"sort_by": [
{"sort": "priority", "by": "desc"},
{"sort": "last_name", "by": "asc"},
{"sort": "first_name", "by": "asc"}
]
}
Pagination Basics
Understanding Pagination
Pagination divides large result sets into manageable pages:
| Parameter | Description | Default | Max |
|---|---|---|---|
page |
Page number to retrieve | 1 | No limit |
limit |
Records per page | 100 | 200 |
Basic Pagination
GET /api/v1/data-tables/{tableId}/records?page=1&limit=50
Pagination Response
{
"type": "success",
"items": [...],
"total_items": 500,
"total_pages": 10,
"current_page": 1,
"limit": 50
}
| Field | Description |
|---|---|
total_items |
Total number of records matching query |
total_pages |
Number of pages available |
current_page |
Current page number |
limit |
Records per page |
Implementing Pagination
Fetching All Pages
async function getAllRecords(tableId) {
const allRecords = [];
let page = 1;
let totalPages = 1;
while (page
Paginated Results with Progress
async function getAllRecordsWithProgress(tableId, onProgress) {
const allRecords = [];
let page = 1;
let totalPages = 1;
while (page {
console.log(`Page ${progress.currentPage}/${progress.totalPages} - ${progress.fetchedSoFar}/${progress.totalRecords} records`);
});
Rate-Limited Pagination
async function getAllRecordsWithRateLimit(tableId, delayMs = 500) {
const allRecords = [];
let page = 1;
let totalPages = 1;
while (page setTimeout(resolve, delayMs));
}
}
return allRecords;
}
Combining Sorting, Filtering, and Pagination
Complete Query Example
POST /api/v1/data-tables/{tableId}/records
Content-Type: application/json
{
"filters": {
"condition": "AND",
"items": [
{
"field_id": "status",
"operator": "is",
"val": "Active"
},
{
"field_id": "created_at",
"operator": "is on or after",
"val": "2024-01-01"
}
]
},
"sort_by": [
{"sort": "priority", "by": "desc"},
{"sort": "created_at", "by": "asc"}
],
"page": 1,
"limit": 50,
"fields": "id,name,status,priority,created_at"
}
This query:
- Filters for Active records created in 2024
- Sorts by priority (high to low), then by date (old to new)
- Returns page 1 with 50 records
- Only includes specified fields
Performance Optimization
1. Use Appropriate Page Size
// ❌ Bad: Too small, many requests
?page=1&limit=10 // Need 100 requests for 1000 records
// ✅ Good: Larger pages, fewer requests
?page=1&limit=100 // Only 10 requests for 1000 records
2. Limit Fields Returned
// ❌ Bad: Fetches all fields (slower)
?page=1&limit=100
// ✅ Good: Only needed fields (faster)
?page=1&limit=100&fields=id,name,email
3. Use Cursor-Based Pagination for Large Datasets
For very large datasets, consider tracking the last record ID:
// First request
GET /records?limit=100&order=id&order_by=asc
// Subsequent requests (where last_id is the ID of the last record from previous page)
GET /records?limit=100&order=id&order_by=asc&filters[items][0][field_id]=id&filters[items][0][operator]=>&filters[items][0][val]=last_id
4. Cache Results When Appropriate
class PaginatedCache {
constructor(ttl = 300000) { // 5 minutes default
this.cache = new Map();
this.ttl = ttl;
}
getKey(tableId, page, limit) {
return `${tableId}-${page}-${limit}`;
}
get(tableId, page, limit) {
const key = this.getKey(tableId, page, limit);
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp
Common Pagination Patterns
Infinite Scroll
class InfiniteScroll {
constructor(tableId) {
this.tableId = tableId;
this.currentPage = 1;
this.hasMore = true;
this.loading = false;
}
async loadNextPage() {
if (this.loading || !this.hasMore) return null;
this.loading = true;
try {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${this.tableId}/records?page=${this.currentPage}&limit=50`,
{ headers }
);
const data = await response.json();
this.hasMore = this.currentPage {
if (nearBottomOfPage() && scroller.hasMore) {
const nextPage = await scroller.loadNextPage();
appendRecords(nextPage);
}
});
Page Navigation UI
async function getPageInfo(tableId, currentPage = 1, limit = 50) {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${tableId}/records?page=${currentPage}&limit=${limit}`,
{ headers }
);
const data = await response.json();
return {
items: data.items,
currentPage: data.current_page,
totalPages: data.total_pages,
totalItems: data.total_items,
hasPrevious: data.current_page > 1,
hasNext: data.current_page
Jump to Page
async function jumpToPage(tableId, pageNumber, limit = 50) {
// Validate page number
if (pageNumber data.total_pages) {
throw new Error(`Page ${pageNumber} does not exist. Only ${data.total_pages} pages available.`);
}
return data;
}
Sorting Field Types
Sorting Behavior by Field Type
| Field Type | Ascending (asc) | Descending (desc) |
|---|---|---|
| Text | A to Z | Z to A |
| Number/Currency | Smallest to largest | Largest to smallest |
| Date/DateTime | Oldest to newest | Newest to oldest |
| Decision Box | Unchecked first (0, 1) | Checked first (1, 0) |
| Select/Radio | Alphabetical by option | Reverse alphabetical |
Empty/Null Values
Empty or null values are typically sorted to the end regardless of sort direction.
Best Practices
- Always use pagination: Never try to fetch all records at once without pagination
- Choose appropriate page size: Balance between too many requests (small pages) and slow responses (large pages)
- Respect rate limits: Add delays when fetching multiple pages
- Show progress: For large datasets, show users progress indicators
- Cache when possible: Cache pages that don't change frequently
- Optimize sorting: Sort on indexed fields when possible for better performance
- Limit fields: Only fetch fields you need to display
- Handle errors: Implement error handling for pagination edge cases
Complete Example: Paginated Data Table
class DataTable {
constructor(tableId, pageSize = 50) {
this.tableId = tableId;
this.pageSize = pageSize;
this.currentPage = 1;
this.sortField = 'created_at';
this.sortDirection = 'desc';
}
async loadPage() {
const response = await fetch(
`https://api.tadabase.io/api/v1/data-tables/${this.tableId}/records`,
{
method: 'POST',
headers: {
'X-Tadabase-App-id': 'your_app_id',
'X-Tadabase-App-Key': 'your_app_key',
'X-Tadabase-App-Secret': 'your_app_secret',
'Content-Type': 'application/json'
},
body: JSON.stringify({
sort_by: [
{
sort: this.sortField,
by: this.sortDirection
}
],
page: this.currentPage,
limit: this.pageSize
})
}
);
return await response.json();
}
async nextPage() {
this.currentPage++;
return await this.loadPage();
}
async previousPage() {
if (this.currentPage > 1) {
this.currentPage--;
return await this.loadPage();
}
return null;
}
async goToPage(page) {
this.currentPage = page;
return await this.loadPage();
}
async sort(field, direction = 'asc') {
this.sortField = field;
this.sortDirection = direction;
this.currentPage = 1; // Reset to first page
return await this.loadPage();
}
}
// Usage
const table = new DataTable('lGArg7rmR6', 50);
// Load first page
const data = await table.loadPage();
renderTable(data.items);
renderPagination(data);
// Sort by name
await table.sort('name', 'asc');
// Navigate pages
await table.nextPage();
await table.previousPage();
await table.goToPage(5);
Next Steps
Now that you can sort and paginate results, learn about working with table and field metadata:
Discover how to programmatically access table structure, field definitions, and metadata.
We'd love to hear your feedback.