Skip to content

Document Store: Indexing

Document Store: Indexing

Part of: HeliosDB Document Store User Guide

Indexing

Why Index?

Without Index (Full Collection Scan):

Query time: 45ms for 1,000 documents
Query time: 450ms for 10,000 documents
Query time: 4,500ms for 100,000 documents

With Index:

Query time: 2.8ms for 1,000 documents
Query time: 3.1ms for 10,000 documents
Query time: 4.2ms for 100,000 documents

Single-Field Indexes

Create Index:

use mongodb::options::IndexOptions;
// Simple index
let index = IndexModel::builder()
.keys(doc! { "email": 1 }) // 1 = ascending, -1 = descending
.build();
collection.create_index(index, None).await?;
// Unique index
let index = IndexModel::builder()
.keys(doc! { "email": 1 })
.options(IndexOptions::builder().unique(true).build())
.build();
collection.create_index(index, None).await?;

HeliosDB Native:

use heliosdb_document::{IndexDefinition, IndexType};
let definition = IndexDefinition {
name: "email_idx".to_string(),
collection: Collection::new("users"),
index_type: IndexType::SingleField {
field: "email".to_string(),
unique: true,
},
created_at: chrono::Utc::now(),
};
store.create_index(definition)?;

Performance Impact:

  • Build time: ~150ms for 100K documents
  • Query time: 2.8ms (vs 45ms unindexed)
  • Storage overhead: ~5-10% of collection size

Compound Indexes

Create Compound Index:

// Index on multiple fields
let index = IndexModel::builder()
.keys(doc! {
"lastName": 1,
"firstName": 1,
"age": -1 // Descending for age
})
.build();
collection.create_index(index, None).await?;

Index Prefix Rule:

// This compound index: { "lastName": 1, "firstName": 1, "age": -1 }
// Can be used for:
{ "lastName": "Smith" }
{ "lastName": "Smith", "firstName": "John" }
{ "lastName": "Smith", "firstName": "John", "age": { "$gt": 25 } }
// Cannot be used for:
❌ { "firstName": "John" } // Missing lastName prefix
❌ { "age": { "$gt": 25 } } // Missing lastName and firstName

HeliosDB Native:

let definition = IndexDefinition {
name: "name_age_idx".to_string(),
collection: Collection::new("users"),
index_type: IndexType::Compound {
fields: vec![
"lastName".to_string(),
"firstName".to_string(),
"age".to_string(),
],
unique: false,
},
created_at: chrono::Utc::now(),
};

Array Indexes (Multikey)

Index Array Fields:

// Index on array field
let index = IndexModel::builder()
.keys(doc! { "skills": 1 })
.build();
collection.create_index(index, None).await?;
// Query uses index
collection.find(doc! { "skills": "Rust" }, None).await?; // Fast!
collection.find(doc! { "skills": { "$in": ["Rust", "MongoDB"] } }, None).await?; // Fast!

HeliosDB Native:

let definition = IndexDefinition {
name: "skills_idx".to_string(),
collection: Collection::new("users"),
index_type: IndexType::Multikey {
field: "skills".to_string(),
},
created_at: chrono::Utc::now(),
};

Array Index Limitations:

  • Can’t have compound index on two array fields
  • Index size: O(n × m) where n = docs, m = avg array length

Create Text Index:

// Single field
let index = IndexModel::builder()
.keys(doc! { "description": "text" })
.build();
collection.create_index(index, None).await?;
// Multiple fields with weights
let index = IndexModel::builder()
.keys(doc! {
"title": "text",
"description": "text",
"tags": "text"
})
.options(IndexOptions::builder()
.weights(doc! {
"title": 3, // Title matches weighted 3x
"description": 2, // Description 2x
"tags": 1 // Tags 1x
})
.build())
.build();
collection.create_index(index, None).await?;

Full-Text Search:

// Search across indexed fields
collection.find(doc! {
"$text": { "$search": "rust database programming" }
}, None).await?;
// Phrase search
collection.find(doc! {
"$text": { "$search": "\"rust programming\"" } // Exact phrase
}, None).await?;
// Exclude terms
collection.find(doc! {
"$text": { "$search": "database -mongodb" } // Contains "database" but not "mongodb"
}, None).await?;

HeliosDB Native:

use std::collections::HashMap;
let mut weights = HashMap::new();
weights.insert("title".to_string(), 3.0);
weights.insert("description".to_string(), 2.0);
let definition = IndexDefinition {
name: "content_text_idx".to_string(),
collection: Collection::new("articles"),
index_type: IndexType::Text {
fields: vec!["title".to_string(), "description".to_string()],
weights,
},
created_at: chrono::Utc::now(),
};

Geospatial Indexes (2dsphere)

Create Geospatial Index:

// GeoJSON format: { "type": "Point", "coordinates": [longitude, latitude] }
let index = IndexModel::builder()
.keys(doc! { "location": "2dsphere" })
.build();
collection.create_index(index, None).await?;

Geospatial Queries:

// Find nearby locations (within 5km)
collection.find(doc! {
"location": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [-122.4194, 37.7749] // San Francisco
},
"$maxDistance": 5000 // 5km in meters
}
}
}, None).await?;
// Find within polygon
collection.find(doc! {
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon",
"coordinates": [[
[-122.5, 37.8],
[-122.3, 37.8],
[-122.3, 37.7],
[-122.5, 37.7],
[-122.5, 37.8]
]]
}
}
}
}, None).await?;

HeliosDB Native:

let definition = IndexDefinition {
name: "location_2dsphere_idx".to_string(),
collection: Collection::new("places"),
index_type: IndexType::Geospatial {
field: "location".to_string(),
index_type: GeoIndexType::TwoDSphere,
},
created_at: chrono::Utc::now(),
};

Wildcard Indexes

Index All Fields:

// Index all fields in document
let index = IndexModel::builder()
.keys(doc! { "$**": 1 })
.build();
collection.create_index(index, None).await?;
// Index all fields under specific path
let index = IndexModel::builder()
.keys(doc! { "user.$**": 1 })
.build();
collection.create_index(index, None).await?;

HeliosDB Native:

let definition = IndexDefinition {
name: "user_wildcard_idx".to_string(),
collection: Collection::new("users"),
index_type: IndexType::Wildcard {
pattern: "user.*".to_string(),
},
created_at: chrono::Utc::now(),
};

Partial Indexes

Index Subset of Documents:

// Index only active users
let index = IndexModel::builder()
.keys(doc! { "email": 1 })
.options(IndexOptions::builder()
.partial_filter_expression(doc! { "status": "active" })
.build())
.build();
collection.create_index(index, None).await?;
// This query uses index (matches filter)
collection.find(doc! {
"email": "alice@example.com",
"status": "active"
}, None).await?;
// This query does NOT use index (doesn't match filter)
collection.find(doc! {
"email": "alice@example.com",
"status": "inactive"
}, None).await?;

HeliosDB Native:

let definition = IndexDefinition {
name: "active_email_idx".to_string(),
collection: Collection::new("users"),
index_type: IndexType::Partial {
filter: Filter::eq("status", json!("active")),
index: Box::new(IndexType::SingleField {
field: "email".to_string(),
unique: true,
}),
},
created_at: chrono::Utc::now(),
};

Index Management

List Indexes:

let indexes = collection.list_indexes(None).await?;
for index in indexes {
println!("{:?}", index);
}

Drop Index:

collection.drop_index("email_idx", None).await?;

Index Statistics:

// Get collection stats including index usage
let stats = db.run_command(doc! {
"collStats": "users",
"indexDetails": true
}, None).await?;
println!("Index stats: {:?}", stats);

Index Performance Guidelines

Collection SizeRecommended IndexesNotes
< 1K docsNoneFull scan is fast enough
1K - 10K docs1-3 indexesIndex frequently queried fields
10K - 100K docs3-7 indexesCompound indexes for common queries
100K - 1M docs5-15 indexesConsider partial indexes
> 1M docs10-30 indexesMonitor index usage, remove unused

Index Size Impact:

  • Single-field index: ~5-10% of collection size
  • Compound index (3 fields): ~15-20%
  • Text index: ~30-50% (due to term dictionary)
  • Geospatial index: ~10-15%

Navigation: ← Previous: Query Language | Back to Index | Next: Aggregation Framework →