Collections & Schemas
Collections are containers for your data, similar to tables in traditional databases. Each collection can have an optional schema that enforces data structure, types, and validation rules.
- Collection - The data container itself
- Schema - The validation rules and structure definition for that collection
Create Collection
Create a new collection with optional schema validation.
Creating collections requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
use std::collections::HashMap;
client.create_collection(
"users",
Some(Schema {
fields: [
("name".to_string(), FieldSchema { field_type: "String", required: true, ..Default::default() }),
("email".to_string(), FieldSchema { field_type: "String", required: true, ..Default::default() }),
("age".to_string(), FieldSchema { field_type: "Number", required: false, ..Default::default() }),
].into_iter().collect(),
})
).await?;
client.create_collection('users', {
'fields': {
'name': {'type': 'String', 'required': True},
'email': {'type': 'String', 'required': True},
'age': {'type': 'Number'}
}
})
await client.createCollection('users', {
fields: {
name: { type: 'String', required: true },
email: { type: 'String', required: true },
age: { type: 'Number' }
}
});
await client.createCollection('users', {
fields: {
name: { type: 'String', required: true },
email: { type: 'String', required: true },
age: { type: 'Number' }
}
});
client.createCollection("users", mapOf(
"fields" to mapOf(
"name" to mapOf("type" to "String", "required" to true),
"email" to mapOf("type" to "String", "required" to true),
"age" to mapOf("type" to "Number")
)
))
client.CreateCollection("users", map[string]interface{}{
"fields": map[string]interface{}{
"name": map[string]interface{}{"type": "String", "required": true},
"email": map[string]interface{}{"type": "String", "required": true},
"age": map[string]interface{}{"type": "Number"},
},
})
curl -X POST https://{EKODB_API_URL}/api/collections/users \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"name": {
"type": "String",
"required": true
},
"email": {
"type": "String",
"required": true
},
"age": {
"type": "Number"
}
}
}'
# Response
{
"status": "success",
"message": "Collection created successfully"
}
Get Collection Info
Retrieve metadata about a collection.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
let info = client.get_collection_info("users").await?;
println!("Records: {}", info.record_count);
println!("Schema: {:?}", info.schema);
info = client.get_collection_info('users')
print(info['record_count']) # 1234
print(info['schema'])
const info = await client.getCollectionInfo('users');
console.log(info.record_count); // 1234
console.log(info.schema);
const info = await client.getCollectionInfo('users');
console.log(info.record_count); // 1234
console.log(info.schema);
val info = client.getCollectionInfo("users")
println("Records: ${info.recordCount}")
println("Schema: ${info.schema}")
info, err := client.GetCollectionInfo("users")
fmt.Println("Records:", info.RecordCount)
fmt.Println("Schema:", info.Schema)
curl https://{EKODB_API_URL}/api/collections/users \
-H "Authorization: Bearer {TOKEN}"
# Response
{
"name": "users",
"record_count": 1234,
"created_at": "2026-01-10T08:00:00Z",
"schema": {
"fields": {
"name": {"type": "String", "required": true},
"email": {"type": "String", "required": true}
}
}
}
List All Collections
Get a list of all collections in the database.
Listing all collections requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
let collections = client.list_collections().await?;
println!("{:?}", collections);
collections = client.list_collections()
print(collections)
const collections = await client.listCollections();
console.log(collections);
const collections = await client.listCollections();
console.log(collections);
val collections = client.listCollections()
println(collections)
collections, err := client.ListCollections()
fmt.Println(collections)
curl https://{EKODB_API_URL}/api/collections \
-H "Authorization: Bearer {ADMIN_TOKEN}"
# Response
{
"collections": [
"users",
"products",
"orders"
]
}
Delete Collection
Delete an entire collection and all its records permanently.
This operation requires Admin access and is irreversible. Use with extreme caution.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
client.delete_collection("users").await?;
client.delete_collection('users')
await client.deleteCollection('users');
await client.deleteCollection('users');
client.deleteCollection("users")
err := client.DeleteCollection("users")
curl -X DELETE https://{EKODB_API_URL}/api/collections/{collection} \
-H "Authorization: Bearer {ADMIN_TOKEN}"
# Response
{
"status": "success",
"message": "Collection deleted successfully"
}
Restore Record from Trash
Restore a previously deleted record from trash. Records remain in trash for 30 days before permanent deletion.
Restoring records from trash requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
client.restore_from_trash("users", &record_id).await?;
client.restore_from_trash('users', record_id)
await client.restoreFromTrash('users', recordId);
await client.restoreFromTrash('users', recordId);
client.restoreFromTrash("users", recordId)
err := client.RestoreFromTrash("users", recordId)
curl -X POST https://{EKODB_API_URL}/api/trash/{collection}/{record_id} \
-H "Authorization: Bearer {ADMIN_TOKEN}"
# Response
{
"status": "restored",
"id": "record_id_123",
"collection": "users"
}
Restore Collection from Trash
Restore all deleted records in a collection from trash.
Restoring collections from trash requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
let result = client.restore_collection_from_trash("users").await?;
println!("Restored: {} records", result.records_restored);
result = client.restore_collection_from_trash('users')
print(result['records_restored'])
const result = await client.restoreCollectionFromTrash('users');
console.log(result.records_restored);
const result = await client.restoreCollectionFromTrash('users');
console.log(result.records_restored);
val result = client.restoreCollectionFromTrash("users")
println("Restored: ${result.recordsRestored} records")
result, err := client.RestoreCollectionFromTrash("users")
fmt.Printf("Restored: %d records\n", result.RecordsRestored)
curl -X POST https://{EKODB_API_URL}/api/trash/{collection} \
-H "Authorization: Bearer {ADMIN_TOKEN}"
# Response
{
"status": "restored",
"collection": "users",
"records_restored": 42
}
Deleted records are kept in trash for 30 days. After this period, they are permanently deleted and cannot be restored.
Get Schema
Retrieve the current schema for a collection.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
let schema = client.get_schema("users").await?;
println!("{:?}", schema.fields);
schema = client.get_schema('users')
print(schema['fields'])
const schema = await client.getSchema('users');
console.log(schema.fields);
const schema = await client.getSchema('users');
console.log(schema.fields);
val schema = client.getSchema("users")
println(schema.fields)
schema, err := client.GetSchema("users")
fmt.Println(schema.Fields)
curl https://{EKODB_API_URL}/api/schemas/{collection} \
-H "Authorization: Bearer {ADMIN_TOKEN}"
# Response
{
"fields": {
"name": {
"type": "String",
"required": true,
"minLength": 2
},
"email": {
"type": "String",
"required": true
},
"age": {
"type": "Integer",
"min": 0,
"max": 150
}
}
}
Update Schema Constraints
Update validation constraints for an existing schema.
Updating schema constraints requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
client.update_schema("users", Schema {
fields: [
("email".to_string(), FieldSchema {
field_type: "String",
required: true,
..Default::default()
}),
("age".to_string(), FieldSchema {
field_type: "Integer",
min: Some(18),
max: Some(100),
..Default::default()
}),
].into_iter().collect(),
}).await?;
client.update_schema('users', {
'fields': {
'email': {
'type': 'String',
'required': True
},
'age': {
'type': 'Integer',
'min': 18,
'max': 100
}
}
})
await client.updateSchema('users', {
fields: {
email: {
type: 'String',
required: true
},
age: {
type: 'Integer',
min: 18,
max: 100
}
}
});
await client.updateSchema('users', {
fields: {
email: {
type: 'String',
required: true
},
age: {
type: 'Integer',
min: 18,
max: 100
}
}
});
client.updateSchema("users", mapOf(
"fields" to mapOf(
"email" to mapOf(
"type" to "String",
"required" to true
),
"age" to mapOf(
"type" to "Integer",
"min" to 18,
"max" to 100
)
)
))
client.UpdateSchema("users", map[string]interface{}{
"fields": map[string]interface{}{
"email": map[string]interface{}{
"type": "String",
"required": true,
},
"age": map[string]interface{}{
"type": "Integer",
"min": 18,
"max": 100,
},
},
})
curl -X PUT https://{EKODB_API_URL}/api/schemas/{collection} \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"email": {
"type": "String",
"required": true
},
"age": {
"type": "Integer",
"min": 18,
"max": 100
}
}
}'
# Response
{
"message": "Schema updated successfully"
}
Schema updates only affect new records. Existing records are not automatically migrated or validated against the new schema.
Set Primary Key Alias
Configure a custom field to use as the primary key instead of the default id.
Setting a primary key alias requires admin permissions.
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
client.set_primary_key_alias("products", "sku").await?;
client.set_primary_key_alias('products', 'sku')
await client.setPrimaryKeyAlias('products', 'sku');
await client.setPrimaryKeyAlias('products', 'sku');
client.setPrimaryKeyAlias("products", "sku")
err := client.SetPrimaryKeyAlias("products", "sku")
curl -X PUT https://{EKODB_API_URL}/api/schemas/{collection}/primary-key-alias \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"alias": "sku"
}'
# Response
{
"message": "Primary key alias set successfully",
"alias": "sku"
}
Example - Using Custom Primary Key:
- Client Libraries (Recommended)
- Direct API
- 🦀 Rust
- 🐍 Python
- 📘 TypeScript
- 📦 JavaScript
- 🟣 Kotlin
- 🔷 Go
use ekodb_client::Record;
// Insert with custom primary key
let mut user = Record::new();
user.insert("user_id", "custom_user_001");
user.insert("name", "John Doe");
user.insert("email", "john@example.com");
let result = client.insert("users", user).await?;
// Retrieve using custom primary key
let user = client.find_by_id("users", "custom_user_001").await?;
println!("Found user: {:?}", user);
# Insert with custom primary key
user = {
"user_id": "custom_user_001",
"name": "John Doe",
"email": "john@example.com"
}
result = await client.insert("users", user)
# Retrieve using custom primary key
user = await client.find_by_id("users", "custom_user_001")
print(f"Found user: {user}")
// Insert with custom primary key
const user = {
user_id: "custom_user_001",
name: "John Doe",
email: "john@example.com"
};
const result = await client.insert("users", user);
// Retrieve using custom primary key
const found = await client.findById("users", "custom_user_001");
console.log("Found user:", found);
// Insert with custom primary key
const user = {
user_id: "custom_user_001",
name: "John Doe",
email: "john@example.com"
};
const result = await client.insert("users", user);
// Retrieve using custom primary key
const found = await client.findById("users", "custom_user_001");
console.log("Found user:", found);
import io.ekodb.client.types.Record
// Insert with custom primary key
val user = Record.new()
.insert("user_id", "custom_user_001")
.insert("name", "John Doe")
.insert("email", "john@example.com")
val result = client.insert("users", user)
// Retrieve using custom primary key
val found = client.findById("users", "custom_user_001")
println("Found user: $found")
// Insert with custom primary key
user := map[string]interface{}{
"user_id": "custom_user_001",
"name": "John Doe",
"email": "john@example.com",
}
result, err := client.Insert("users", user)
if err != nil {
log.Fatal(err)
}
// Retrieve using custom primary key
found, err := client.FindByID("users", "custom_user_001")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found user: %+v\n", found)
# Insert with custom primary key
curl -X POST https://{EKODB_API_URL}/api/insert/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {YOUR_API_TOKEN}" \
-d '{
"user_id": "custom_user_001",
"name": "John Doe",
"email": "john@example.com"
}'
# Retrieve using custom primary key
curl -X GET https://{EKODB_API_URL}/api/find/users/custom_user_001 \
-H "Authorization: Bearer {YOUR_API_TOKEN}"
Schema Field Types
Supported Data Types
| Type | Description | Validation Options |
|---|---|---|
String | Text values | max_length, min_length, pattern |
Integer | 64-bit signed integers | min, max |
Float | 64-bit floating-point numbers | min, max |
Number | Integers and floats | min, max |
Boolean | True/false values | None |
Array | Lists of values | items, min_items, max_items |
Object | Nested JSON objects | properties |
DateTime | RFC 3339 datetime strings | format |
Decimal | Arbitrary-precision decimals | min, max |
UUID | RFC 4122 identifiers | None |
Vector | Numeric arrays for embeddings | None |
Set | Unique value collections | min_items, max_items |
Binary | Base64-encoded binary data | None |
Bytes | Raw byte arrays | None |
Duration | Time span values | None |
Field Constraints
String Constraints:
{
"username": {
"type": "String",
"required": true,
"min_length": 3,
"max_length": 20,
"pattern": "^[a-zA-Z0-9_]+$"
}
}
Number Constraints:
{
"age": {
"type": "Number",
"min": 0,
"max": 150
},
"price": {
"type": "Number",
"min": 0.01,
"max": 999999.99
}
}
Array Constraints:
{
"tags": {
"type": "Array",
"items": {
"type": "String",
"max_length": 50
},
"min_items": 1,
"max_items": 10
}
}
Enum Validation:
{
"status": {
"type": "String",
"enum": ["draft", "published", "archived"],
"default": "draft"
}
}
Nested Objects:
{
"address": {
"type": "Object",
"properties": {
"street": {
"type": "String",
"required": true
},
"city": {
"type": "String",
"required": true
},
"postal_code": {
"type": "String",
"pattern": "^[0-9]{5}$"
}
}
}
}
Complete Example
Here's a complete workflow for creating and managing a collection:
#!/bin/bash
# 1. Create collection with schema
curl -X POST https://{EKODB_API_URL}/api/collections/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-d '{
"fields": {
"sku": {
"type": "String",
"required": true,
"pattern": "^[A-Z0-9-]+$"
},
"name": {
"type": "String",
"required": true,
"max_length": 200
},
"price": {
"type": "Number",
"min": 0.01,
"required": true
},
"category": {
"type": "String",
"enum": ["electronics", "clothing", "books", "food"]
},
"in_stock": {
"type": "Boolean",
"default": true
},
"tags": {
"type": "Array",
"items": {
"type": "String"
},
"max_items": 5
}
}
}'
# 2. Set custom primary key
curl -X PUT https://{EKODB_API_URL}/api/schemas/products/primary-key-alias \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-d '{
"alias": "sku"
}'
# 3. Insert product (validates against schema)
curl -X POST https://{EKODB_API_URL}/api/insert/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {YOUR_API_TOKEN}" \
-d '{
"sku": "ELEC-001",
"name": "Wireless Mouse",
"price": 29.99,
"category": "electronics",
"in_stock": true,
"tags": ["wireless", "bluetooth", "ergonomic"]
}'
# 4. Get collection info
curl -X GET https://{EKODB_API_URL}/api/collections/products \
-H "Authorization: Bearer {YOUR_API_TOKEN}"
# 5. Get current schema
curl -X GET https://{EKODB_API_URL}/api/schemas/products \
-H "Authorization: Bearer {YOUR_API_TOKEN}"
# 6. Update schema constraints
curl -X PUT https://{EKODB_API_URL}/api/schemas/products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-d '{
"fields": {
"sku": {
"type": "String",
"required": true,
"pattern": "^[A-Z0-9-]+$"
},
"name": {
"type": "String",
"required": true,
"max_length": 300
},
"price": {
"type": "Number",
"min": 0.01,
"max": 100000
}
}
}'
Best Practices
Schema Design
Start Simple, Evolve Gradually:
# Initial schema - minimal constraints
{
"fields": {
"name": {"type": "String", "required": true},
"email": {"type": "String", "required": true}
}
}
# Later - add more constraints as requirements clarify
{
"fields": {
"name": {
"type": "String",
"required": true,
"min_length": 2,
"max_length": 100
},
"email": {
"type": "String",
"required": true
}
}
}
Collection Naming
Use Clear, Plural Names:
# Good
/api/collections/users
/api/collections/products
/api/collections/order_items
# Avoid
/api/collections/user
/api/collections/Product
/api/collections/order-item
Schema Validation
Balance Strictness with Flexibility:
{
"fields": {
"core_field": {
"type": "String",
"required": true,
"max_length": 100
},
"optional_field": {
"type": "String",
"required": false
}
}
}
Primary Key Strategy
Choose Based on Your Use Case:
| Use Case | Primary Key Strategy |
|---|---|
| Auto-generated IDs | Use default id field |
| External system sync | Set alias to external ID |
| Natural keys (SKU, email) | Set alias to natural key |
| UUIDs | Set alias to UUID field |
Validation Errors
When a record violates the schema, you'll receive detailed error messages:
# Invalid insert attempt
POST /api/insert/users
{
"name": "A", // Too short
"email": "invalid-email", // Invalid format
"age": 200 // Exceeds max
}
# Error response
{
"error": "Schema validation failed",
"details": [
{
"field": "name",
"constraint": "min_length",
"expected": 2,
"actual": 1,
"message": "Field 'name' must be at least 2 characters"
},
{
"field": "email",
"constraint": "pattern",
"message": "Field 'email' does not match required pattern"
},
{
"field": "age",
"constraint": "max",
"expected": 150,
"actual": 200,
"message": "Field 'age' exceeds maximum value of 150"
}
]
}
Related Documentation
- Basic Operations - Insert, query, update, and delete records
- Indexes - Create indexes for query performance
- Authentication - API key and permission management
- Data Types - Detailed data type reference
Example Code
Direct HTTP/REST API Examples
Raw HTTP examples demonstrating the REST API directly:
- JavaScript:
collection_management.js - Python:
collection_management.py - Go:
collection_management.go - Rust:
collection_management.rs
Client Library Examples
Production-ready examples using official client libraries:
- Rust:
client_collection_management.rs - Python:
client_collection_management.py - TypeScript:
client_collection_management.ts - Go:
client_collection_management.go - Kotlin:
ClientCollectionManagement.kt - JavaScript:
client_collection_management.js