Advanced Features
Manage Indexes
Create and manage indexes for optimal query performance
Index Management
Indexes are essential for database performance. They allow MongoDB to efficiently locate documents without scanning every document in a collection.
Why Use Indexes?
Without an index:
Query: Find player by steamid
Process: Scan ALL documents → Find match → Return
With an index:
Query: Find player by steamid
Process: Look up in index → Jump to document → Return
Creating Indexes
Syntax
local indexName = collection:CreateIndex(keys, unique, name)
Parameters
keys(table): Fields to index with sort direction (1 = ascending, -1 = descending)unique(boolean): Enforce unique valuesname(string): Custom index name
Returns
string: Name of created indexnil: On failure
Index Types
Single Field Index
Index on one field:
-- Ascending index on steamid (unique)
local name = players:CreateIndex(
{ steamid = 1 },
true, -- unique
"steamid_unique"
)
print("Created index:", name)
-- Descending index on level
players:CreateIndex(
{ level = -1 },
false,
"level_desc"
)
Compound Index
Index on multiple fields:
-- Index on class and level
players:CreateIndex(
{ class = 1, level = -1 },
false,
"class_level"
)
-- Useful for queries like:
players:Find({ class = "Warrior", level = { ["$gte"] = 10 } })
Text Index
For text search:
-- Create text index on username
players:CreateIndex(
{ username = "text" },
false,
"username_text"
)
-- Now you can search:
players:Find({
["$text"] = { ["$search"] = "player" }
})
Listing Indexes
Get all indexes on a collection:
local indexes = collection:ListIndexes()
if indexes then
print("Indexes on collection:")
for i, index in ipairs(indexes) do
print(string.format("%d. %s", i, index.name or "unnamed"))
-- Print keys
if index.key then
local keys = {}
for field, direction in pairs(index.key) do
table.insert(keys, field .. ":" .. tostring(direction))
end
print(" Keys: " .. table.concat(keys, ", "))
end
-- Show if unique
if index.unique then
print(" Unique: true")
end
end
end
Dropping Indexes
Drop Specific Index
local success = collection:DropIndex("index_name")
if success then
print("✓ Index dropped")
else
print("✗ Failed to drop index")
end
Drop All Indexes
-- Drop all indexes except _id
collection:DropIndex("*")
The _id index cannot be dropped and is always present.
Index Strategies
For Player Lookups
-- Most common query: find by SteamID
players:CreateIndex(
{ steamid = 1 },
true, -- Unique!
"steamid_unique"
)
For Leaderboards
-- Sort by score descending
players:CreateIndex(
{ score = -1 },
false,
"score_desc"
)
-- Or compound for filtered leaderboards
players:CreateIndex(
{ banned = 1, score = -1 },
false,
"active_score"
)
For Filtering
-- Common filter fields
players:CreateIndex({ class = 1 }, false, "class_index")
players:CreateIndex({ level = 1 }, false, "level_index")
players:CreateIndex({ vip = 1 }, false, "vip_index")
-- Or compound for common query patterns
players:CreateIndex(
{ class = 1, level = 1, vip = 1 },
false,
"filter_compound"
)
For Time-Based Queries
-- Index on timestamps
players:CreateIndex(
{ last_login = -1 },
false,
"recent_login"
)
-- TTL index for auto-expiring documents
-- (Note: TTL indexes are managed by MongoDB server)
Best Practices
1. Index Query Patterns
Create indexes based on how you query:
-- If you query like this:
players:Find({ class = "Warrior", level = { ["$gte"] = 10 } })
-- Create this index:
players:CreateIndex({ class = 1, level = 1 }, false, "class_level")
2. Consider Index Direction
Direction matters for sorting:
-- For descending sorts (highest first)
players:CreateIndex({ score = -1 }, false, "score_desc")
-- Query uses the index efficiently
players:Find({}, { sort = { score = -1 } })
3. Compound Index Order
Put equality filters before range filters:
-- Good: Equality (class) before range (level)
{ class = 1, level = 1 }
-- For query:
{ class = "Warrior", level = { ["$gte"] = 10 } }
4. Don't Over-Index
Each index:
- Uses disk space
- Slows down writes
- Needs maintenance
Only create indexes you need.
5. Use Unique for Identifiers
-- Prevent duplicate SteamIDs
players:CreateIndex({ steamid = 1 }, true, "steamid_unique")
-- Trying to insert duplicate will fail
Practical Examples
Setup for Player System
function SetupPlayerIndexes()
local players = db:Collection("players")
-- Primary lookup
players:CreateIndex(
{ steamid = 1 },
true,
"steamid_unique"
)
-- Leaderboard
players:CreateIndex(
{ score = -1 },
false,
"score_desc"
)
-- Active players
players:CreateIndex(
{ last_login = -1 },
false,
"recent_login"
)
-- Filtering
players:CreateIndex(
{ class = 1, level = 1 },
false,
"class_level"
)
print("✓ Player indexes created")
end
-- Call on server start
SetupPlayerIndexes()
Setup for Logs
function SetupLogIndexes()
local logs = db:Collection("logs")
-- Query by category
logs:CreateIndex(
{ category = 1, timestamp = -1 },
false,
"category_time"
)
-- Query by player
logs:CreateIndex(
{ steamid = 1, timestamp = -1 },
false,
"player_time"
)
print("✓ Log indexes created")
end
Index Management Utility
local IndexManager = {}
function IndexManager.EnsureIndexes(collection, indexes)
local existing = collection:ListIndexes() or {}
local existingNames = {}
for _, idx in ipairs(existing) do
existingNames[idx.name] = true
end
for _, index in ipairs(indexes) do
if not existingNames[index.name] then
local created = collection:CreateIndex(
index.keys,
index.unique or false,
index.name
)
if created then
print("Created index:", index.name)
end
end
end
end
-- Usage
IndexManager.EnsureIndexes(players, {
{ name = "steamid_unique", keys = { steamid = 1 }, unique = true },
{ name = "score_desc", keys = { score = -1 } },
{ name = "class_level", keys = { class = 1, level = 1 } }
})
Monitoring Index Usage
Check if your queries use indexes:
-- List indexes to verify they exist
local indexes = collection:ListIndexes()
print("Current indexes:")
for _, index in ipairs(indexes) do
print(" -", index.name)
end
-- Get collection stats
local stats = db:Stats("players")
if stats then
print("Index size:", stats.totalIndexSize, "bytes")
end
Next Steps
- Examples - See indexes in real applications
- API Reference - Complete method documentation