Indexes
Indexes improve query performance by allowing the database to look up documents without scanning the entire collection. PocketDB supports three index types.
Installation
Add PocketDB to your Cargo.toml:
toml
[dependencies]
pocketdb = "0.1"Or via the command line:
bash
cargo add pocketdbB+Tree Index
B+Tree indexes support equality lookups, range queries, and sorted retrieval.
Creating a B+Tree Index
rust
use pocketdb::index::IndexSpec;
// Single field index (default type)
users.create_index(IndexSpec::single("email"))?;
// Unique index
users.create_index(IndexSpec::single("email").unique(true))?;
// Compound index (covers multiple fields)
users.create_index(IndexSpec::compound(&["last_name", "first_name"]))?;
// Custom name
users.create_index(IndexSpec::single("email").name("user_email_idx"))?;When to Use B+Tree
- Range queries:
age > 18,price BETWEEN 10 AND 100 - Sorted results
- Equality lookups that also need ordering
Range Queries with B+Tree
rust
use pocketdb::query::BTreeIndex;
// After creating an index, you can use range queries
// The B+Tree index supports range(), range_from(), and range_to() methodsHash Index
Hash indexes provide O(1) average-case equality lookups but don't support range queries.
Creating a Hash Index
rust
use pocketdb::index::IndexSpec;
users.create_index(IndexSpec::single("username").hash())?;When to Use Hash
- Exact equality lookups only
- High-throughput key-value lookups
- When range queries are not needed
TTL Index
TTL (Time-To-Live) indexes automatically track document expiration times.
Creating a TTL Index
rust
use pocketdb::index::IndexSpec;
// Expire documents 24 hours (in ms) after their creation timestamp
users.create_index(
IndexSpec::single("created_at").ttl(24 * 60 * 60 * 1000)
)?;
// Expire session documents after 30 minutes
sessions.create_index(
IndexSpec::single("last_active").ttl(30 * 60 * 1000)
)?;Querying Expired Documents
rust
use pocketdb::index::TtlIndex;
// Get all document IDs that have expired
let expired = ttl_index.expired_documents();When to Use TTL
- Session management
- Temporary tokens
- Cache entries with expiration
- Log retention
Index Management
Listing Indexes
rust
let indexes = users.list_indexes();
for name in &indexes {
println!("Index: {}", name);
}Dropping Indexes
rust
users.drop_index("email_idx")?;Index Constraints
Unique Indexes
rust
// This will error if a document with the same email already exists
users.create_index(IndexSpec::single("email").unique(true))?;
// Inserting a duplicate key fails with PocketError::DuplicateKey
users.insert(doc! { "email" => "alice@example.com" })?;
// This fails:
users.insert(doc! { "email" => "alice@example.com" })?;
// Error: DuplicateKey { index: "email_idx", document: "..." }Query Plan Explanation
Use explain to see which index a query uses:
rust
use pocketdb::filter;
// With an index on "email"
let plan = users.explain(&filter! { "email" => == "alice@example.com" });
// scan_type: IndexLookup("email_idx")
// used_index: Some("email_idx")
// Without a matching index
let plan = users.explain(&filter! { "age" => > 18 });
// scan_type: FullScan
// used_index: NonePerformance Tips
- Index frequently queried fields — fields used in
filter!expressions - Use unique indexes for fields that must be unique (email, username)
- Avoid over-indexing — each index adds overhead to inserts
- Use compound indexes for queries that filter on multiple fields together
- Use TTL indexes for data that should expire automatically
- Check query plans with
explain()to verify indexes are being used