List Records
Retrieve multiple records from your Boltic Tables with powerful querying, filtering, pagination, and sorting capabilities. The SDK provides comprehensive methods for fetching data efficiently.
List Operations
The SDK provides two approaches for retrieving multiple records:
findAll() - List Records
Retrieve multiple records with advanced querying capabilities.
client.records.findAll(tableName: string, options?: RecordQueryOptions): Promise<ApiResponse<RecordWithId[]>>
RecordQueryOptions Interface
interface RecordQueryOptions {
page?: {
page_no: number; // Page number (1-based)
page_size: number; // Records per page
};
filters?: ApiFilter[] | Record<string, unknown>;
sort?: Record<string, unknown>[];
fields?: string[]; // Select specific fields only
}
Examples
Direct Approach
import { createClient } from "@boltic/sdk";
const client = createClient("your-api-key");
// Get all records (with default pagination)
const { data: records, error } = await client.records.findAll("users");
if (error) {
console.error("Query failed:", error.message);
} else {
console.log(`Found ${records.length} records`);
records.forEach((record) => {
console.log(`${record.id}: ${record.name} - ${record.email}`);
});
}
Pagination
Basic Pagination
// Get first page with 20 records per page
const { data: records, pagination } = await client.records.findAll("users", {
page: {
page_no: 1,
page_size: 20,
},
});
console.log(`Page ${pagination.current_page} of ${pagination.total_pages}`);
console.log(`Showing ${records.length} of ${pagination.total_count} total records`);
Pagination Loop
async function getAllRecords(tableName: string, pageSize = 100) {
let allRecords = [];
let currentPage = 1;
let hasMore = true;
while (hasMore) {
const {
data: records,
pagination,
error,
} = await client.records.findAll(tableName, {
page: {
page_no: currentPage,
page_size: pageSize,
},
});
if (error) {
console.error(`Error on page ${currentPage}:`, error.message);
break;
}
allRecords.push(...records);
console.log(`Fetched page ${currentPage}: ${records.length} records`);
hasMore = currentPage < pagination.total_pages;
currentPage++;
}
return allRecords;
}
// Usage
const allUsers = await getAllRecords("users", 50);
console.log(`Total records fetched: ${allUsers.length}`);
Sorting
Single Field Sorting
// Sort by creation date (newest first)
const { data: records } = await client.records.findAll("users", {
sort: [{ field: "created_at", direction: "desc" }],
});
// Sort by name (alphabetical)
const { data: records } = await client.records.findAll("users", {
sort: [{ field: "name", direction: "asc" }],
});
Multi-Field Sorting
// Sort by status first, then by creation date
const { data: records } = await client.records.findAll("users", {
sort: [
{ field: "status", direction: "asc" },
{ field: "created_at", direction: "desc" },
],
});
// Sort by priority, then by due date, then by name
const { data: tasks } = await client.records.findAll("tasks", {
sort: [
{ field: "priority", direction: "desc" }, // High priority first
{ field: "due_date", direction: "asc" }, // Earliest due date first
{ field: "title", direction: "asc" }, // Alphabetical by title
],
});
Sorting Different Data Types
// Numeric sorting
const { data: products } = await client.records.findAll("products", {
sort: [{ field: "price", direction: "desc" }], // Most expensive first
});
// Date sorting
const { data: events } = await client.records.findAll("events", {
sort: [{ field: "event_date", direction: "asc" }], // Earliest first
});
// Boolean sorting
const { data: users } = await client.records.findAll("users", {
sort: [{ field: "is_active", direction: "desc" }], // Active users first
});
Field Selection
Select Specific Fields
// Only fetch needed fields for better performance
const { data: records } = await client.records.findAll("users", {
fields: ["id", "name", "email", "status"],
page: { page_no: 1, page_size: 100 },
});
// Fields for dropdown/select options
const { data: options } = await client.records.findAll("categories", {
fields: ["id", "name"],
sort: [{ field: "name", direction: "asc" }],
});
Performance-Optimized Queries
// Minimal data for listing views
const { data: userList } = await client.records.findAll("users", {
fields: ["id", "name", "email", "status", "last_login"],
filters: [{ field: "status", operator: "=", values: ["active"] }],
sort: [{ field: "last_login", direction: "desc" }],
page: { page_no: 1, page_size: 50 },
});
Basic Filtering
Simple Where Conditions
// Exact match
const { data: activeUsers } = await client.records.findAll("users", {
filters: [{ field: "status", operator: "=", values: ["active"] }],
});
// Multiple conditions (AND logic)
const { data: engineers } = await client.records.findAll("users", {
filters: [
{ field: "department", operator: "=", values: ["engineering"] },
{ field: "status", operator: "=", values: ["active"] },
{ field: "is_verified", operator: "=", values: [true] },
],
});
Comparison Operators
// Greater than / Less than
const { data: seniors } = await client.records.findAll("users", {
filters: [
{ field: "age", operator: ">=", values: [30] }, // Age >= 30
{ field: "salary", operator: ">", values: [50000] }, // Salary > 50000
],
});
// Range queries
const { data: midLevel } = await client.records.findAll("users", {
filters: [
{ field: "experience_years", operator: "BETWEEN", values: [2, 10] }, // 2-10 years experience
{ field: "salary", operator: "BETWEEN", values: [40000, 120000] }, // Salary range
],
});
// Array membership
const { data: techTeam } = await client.records.findAll("users", {
filters: [
{
field: "department",
operator: "IN",
values: ["engineering", "product", "design"],
},
],
});
String Filtering
// Case-insensitive search
const { data: results } = await client.records.findAll("users", {
filters: [
{ field: "name", operator: "ILIKE", values: ["%john%"] }, // Contains "john" (case-insensitive)
{ field: "email", operator: "ILIKE", values: ["%@company.com"] }, // Ends with "@company.com"
],
});
// Exact string matching
const { data: results } = await client.records.findAll("users", {
filters: [
{ field: "email", operator: "LIKE", values: ["%gmail.com"] }, // Case-sensitive contains
{ field: "name", operator: "STARTS WITH", values: ["Dr."] }, // Starts with "Dr."
],
});
Date/Time Filtering
// Date comparisons
const { data: recent } = await client.records.findAll("posts", {
filters: [
{ field: "created_at", operator: ">=", values: ["2024-01-01T00:00:00Z"] }, // This year
{
field: "published_at",
operator: "<=",
values: [new Date().toISOString()],
}, // Published by now
],
});
// Date ranges
const { data: thisMonth } = await client.records.findAll("orders", {
filters: [
{
field: "order_date",
operator: "BETWEEN",
values: ["2024-01-01T00:00:00Z", "2024-01-31T23:59:59Z"],
},
],
});
// Special date operators
const { data: recentOrders } = await client.records.findAll("orders", {
filters: [{ field: "order_date", operator: "WITHIN", values: ["last-7-days"] }],
});
Advanced Filtering with ApiFilter
Direct ApiFilter Format
// Using ApiFilter objects directly
const { data: results } = await client.records.findAll("products", {
filters: [
{ field: "category", operator: "=", values: ["electronics"] },
{ field: "price", operator: ">", values: [100] },
{ field: "in_stock", operator: "=", values: [true] },
],
});
FilterBuilder for Complex Queries
import { createFilter } from "@boltic/sdk";
// Build complex filter conditions
const complexFilters = createFilter()
.equals("status", "published")
.greaterThan("views", 1000)
.in("category", ["tech", "business", "science"])
.like("title", "%AI%")
.between("created_at", "2024-01-01T00:00:00Z", "2024-12-31T23:59:59Z")
.build();
const { data: articles } = await client.records.findAll("articles", {
filters: complexFilters,
sort: [{ field: "views", direction: "desc" }],
page: { page_no: 1, page_size: 20 },
});
Null and Empty Checks
// Check for null/empty values
const { data: incomplete } = await client.records.findAll("users", {
filters: [
{ field: "phone", operator: "IS EMPTY", values: [] },
{ field: "bio", operator: "IS NULL", values: [] },
],
});
// Using FilterBuilder
const emptyProfilesFilter = createFilter().isNull("avatar_url").isEmpty("bio").build();
const { data: emptyProfiles } = await client.records.findAll("users", {
filters: emptyProfilesFilter,
});
Vector Search and AI Operations
Similarity Search
// Find similar content using vector similarity
const queryVector = "[0.1, 0.2, 0.3, 0.4, 0.5]";
const { data: similarDocs } = await client.records.findAll("documents", {
filters: [
{
field: "content_vector",
operator: "<->", // Euclidean distance
values: [queryVector],
},
],
sort: [
{ field: "content_vector", direction: "asc" }, // Closest first
],
page: { page_no: 1, page_size: 10 },
});
Different Vector Distance Operators
⚠️ Important Note: Vector values must be passed as strings, not raw arrays. The queryVector
variable should contain a string like "[0.1,0.2,0.3]"
.
// Euclidean distance (L2)
const euclideanResults = await client.records.findAll("embeddings", {
filters: [{ field: "vector", operator: "<->", values: [queryVector] }],
});
// Manhattan distance (L1)
const manhattanResults = await client.records.findAll("embeddings", {
filters: [{ field: "vector", operator: "<+>", values: [queryVector] }],
});
// Cosine distance
const cosineResults = await client.records.findAll("embeddings", {
filters: [{ field: "vector", operator: "<=>", values: [queryVector] }],
});
// Inner product
const innerProductResults = await client.records.findAll("embeddings", {
filters: [{ field: "vector", operator: "*", values: [queryVector] }],
});
Response Format
Successful List Response
interface ListRecordsResponse {
data: RecordWithId[];
pagination: {
current_page: number;
total_pages: number;
total_count: number;
page_size: number;
};
error: null;
}
Error Response
interface ListRecordsErrorResponse {
data: null;
error: {
message: string;
meta?: string[];
};
}
Best Practices
1. Use Pagination
// Good: Always use pagination for large datasets
const { data: records } = await client.records.findAll("users", {
page: { page_no: 1, page_size: 100 },
});
// Avoid: Fetching all records at once
// const { data: records } = await client.records.findAll('users'); // Could be slow
2. Optimize Field Selection
// Good: Only fetch fields you need
const { data: users } = await client.records.findAll("users", {
fields: ["id", "name", "email"], // Minimal fields for listing
page: { page_no: 1, page_size: 50 },
});
// Avoid: Fetching all fields when you only need a few
3. Use Indexed Fields for Filtering
// Good: Filter on indexed fields first
const { data: records } = await client.records.findAll("users", {
filters: [
{ field: "status", operator: "=", values: ["active"] }, // Indexed field - fast
{ field: "department", operator: "=", values: ["engineering"] }, // Indexed field - fast
{ field: "name", operator: "ILIKE", values: ["%john%"] }, // Text search - slower
],
});
4. Implement Proper Error Handling
// Always handle errors and provide fallbacks
const result = await client.records.findAll("users", queryOptions);
if (result.error) {
console.error("Query failed:", result.error.message);
// Show user-friendly message or fallback data
return { users: [], total: 0 };
}
Next Steps
After listing records, you might want to apply advanced filters for more specific queries.