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 documentsQuery time: 450ms for 10,000 documentsQuery time: 4,500ms for 100,000 documentsWith Index:
Query time: 2.8ms for 1,000 documentsQuery time: 3.1ms for 10,000 documentsQuery time: 4.2ms for 100,000 documentsSingle-Field Indexes
Create Index:
use mongodb::options::IndexOptions;
// Simple indexlet index = IndexModel::builder() .keys(doc! { "email": 1 }) // 1 = ascending, -1 = descending .build();
collection.create_index(index, None).await?;
// Unique indexlet 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 fieldslet 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 firstNameHeliosDB 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 fieldlet index = IndexModel::builder() .keys(doc! { "skills": 1 }) .build();
collection.create_index(index, None).await?;
// Query uses indexcollection.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
Text Indexes (Full-Text Search)
Create Text Index:
// Single fieldlet index = IndexModel::builder() .keys(doc! { "description": "text" }) .build();
collection.create_index(index, None).await?;
// Multiple fields with weightslet 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 fieldscollection.find(doc! { "$text": { "$search": "rust database programming" }}, None).await?;
// Phrase searchcollection.find(doc! { "$text": { "$search": "\"rust programming\"" } // Exact phrase}, None).await?;
// Exclude termscollection.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 polygoncollection.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 documentlet index = IndexModel::builder() .keys(doc! { "$**": 1 }) .build();
collection.create_index(index, None).await?;
// Index all fields under specific pathlet 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 userslet 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 usagelet stats = db.run_command(doc! { "collStats": "users", "indexDetails": true}, None).await?;
println!("Index stats: {:?}", stats);Index Performance Guidelines
| Collection Size | Recommended Indexes | Notes |
|---|---|---|
| < 1K docs | None | Full scan is fast enough |
| 1K - 10K docs | 1-3 indexes | Index frequently queried fields |
| 10K - 100K docs | 3-7 indexes | Compound indexes for common queries |
| 100K - 1M docs | 5-15 indexes | Consider partial indexes |
| > 1M docs | 10-30 indexes | Monitor 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 →