Skip to content

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 pocketdb

B+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() methods

Hash 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: None

Performance Tips ​

  1. Index frequently queried fields — fields used in filter! expressions
  2. Use unique indexes for fields that must be unique (email, username)
  3. Avoid over-indexing — each index adds overhead to inserts
  4. Use compound indexes for queries that filter on multiple fields together
  5. Use TTL indexes for data that should expire automatically
  6. Check query plans with explain() to verify indexes are being used

Released under the MIT License. Built by Muhammad Fiaz.