Indexing

Create indexes for fast O(log n) query performance


Overview

Indexes dramatically improve query performance by providing O(log n) lookups instead of O(n) full collection scans. jasonisnthappy uses B-tree indexes for efficient range queries and exact matches.

Without an index, queries must scan every document in the collection. With an index, the database can quickly locate matching documents.

Single Field Index

Create an index on a single field for fast lookups:

// Create index on email field
db.create_index("users", "email", true)?; // true = unique

// Non-unique index
db.create_index("users", "age", false)?;
# Create index on email field
db.create_index("users", "email_idx", "email", unique=True)

# Non-unique index
db.create_index("users", "age_idx", "age", unique=False)
// Create index on email field
db.createIndex('users', 'email_idx', 'email', true); // true = unique

// Non-unique index
db.createIndex('users', 'age_idx', 'age', false);
// Create index on email field
err := db.CreateIndex("users", "email_idx", "email", true) // true = unique

// Non-unique index
err = db.CreateIndex("users", "age_idx", "age", false)

Queries on indexed fields will automatically use the index:

// Fast lookup using index
let user = users.find_one("email is 'alice@example.com'")?;
# Fast lookup using index
user = coll.find_one("email = 'alice@example.com'")
// Fast lookup using index
const user = await users.findOne("email is 'alice@example.com'");
// Fast lookup using index
user, err := users.FindOne("email is 'alice@example.com'")

Compound Index

Create an index on multiple fields together for queries that filter on multiple fields:

// Index on city and age together
db.create_compound_index("users", &["city", "age"], false)?;
# Index on city and age together
db.create_compound_index("users", "city_age_idx", ["city", "age"], unique=False)
// Index on city and age together
db.createCompoundIndex('users', 'city_age_idx', ['city', 'age'], false);
// Index on city and age together
err := db.CreateCompoundIndex("users", "city_age_idx", []string{"city", "age"}, false)

This index speeds up queries that filter on both fields:

// This query will use the compound index
let results = users.find("city is 'NYC' and age > 25")?;
# This query will use the compound index
results = coll.find("city = 'NYC' and age > 25")
// This query will use the compound index
const results = await users.find("city is 'NYC' and age > 25");
// This query will use the compound index
results, err := users.Find("city is 'NYC' and age > 25")

Text Index

Create a full-text search index on one or more fields. See the Text Search guide for detailed usage:

// Create text index on multiple fields
db.create_text_index("posts", "search_idx", &["title", "content", "tags"])?;
# Create text index on single field
db.create_text_index("posts", "search_idx", "content")
// Create text index on multiple fields
db.createTextIndex('posts', 'search_idx', ['title', 'content', 'tags']);
// Create text index on multiple fields
err := db.CreateTextIndex("posts", "search_idx", []string{"title", "content", "tags"})

Use the text index for full-text search:

let results = posts.search("rust database")?;
for result in results {
    println!("Score: {:.2}, Title: {}",
        result.score, result.doc_id);
}
results = coll.search("rust database")
for result in results:
    print(f"Score: {result['score']:.2f}")
const results = await posts.search('rust database');
results.forEach(result => {
    console.log(`Score: ${result.score.toFixed(2)}`);
});
results, err := posts.Search("rust database")
for _, result := range results {
    fmt.Printf("Score: %.2f\n", result.Score)
}

Unique Constraints

Unique indexes prevent duplicate values for a field:

// Create unique index on email
db.create_index("users", "email", true)?;

// Attempting to insert duplicate email will fail
let result = users.insert(json!({
    "email": "alice@example.com" // Error if already exists
}));

match result {
    Err(Error::UniqueConstraintViolation) => {
        println!("Email already exists");
    }
    _ => {}
}
# Create unique index on email
db.create_index("users", "email_idx", "email", unique=True)

# Attempting to insert duplicate email will fail
try:
    coll.insert({"email": "alice@example.com"})
except RuntimeError as e:
    if "unique" in str(e).lower():
        print("Email already exists")
// Create unique index on email
db.createIndex('users', 'email_idx', 'email', true);

// Attempting to insert duplicate email will fail
try {
    await users.insert({ email: 'alice@example.com' });
} catch (err) {
    if (err.message.includes('unique')) {
        console.log('Email already exists');
    }
}
// Create unique index on email
err := db.CreateIndex("users", "email_idx", "email", true)

// Attempting to insert duplicate email will fail
_, err = users.Insert(map[string]interface{}{
    "email": "alice@example.com",
})
if err != nil && strings.Contains(err.Error(), "unique") {
    fmt.Println("Email already exists")
}

List Indexes

List all indexes on a collection:

let indexes = db.list_indexes("users")?;
for index in indexes {
    println!("{}: {:?} (unique: {})",
        index.name,
        index.fields,
        index.unique
    );
}
indexes = db.list_indexes("users")
for idx in indexes:
    print(f"{idx['name']}: {idx['fields']} (unique: {idx['unique']})")
const indexes = db.listIndexes('users');
indexes.forEach(idx => {
    console.log(`${idx.name}: ${idx.fields} (unique: ${idx.unique})`);
});
indexes, err := db.ListIndexes("users")
for _, idx := range indexes {
    fmt.Printf("%s: %v (unique: %v)\n",
        idx.Name,
        idx.Fields,
        idx.Unique
    )
}

Drop Index

Remove an index from a collection:

db.drop_index("users", "email_idx")?;
db.drop_index("users", "email_idx")
db.dropIndex('users', 'email_idx');
err := db.DropIndex("users", "email_idx")

Performance Considerations