V2 brings significant improvements:
Better Performance
Improved connection pooling and async runtime
New Features
Bulk operations, aggregation, indexes
Better Errors
Detailed error messages and logging
Cleaner API
More explicit method names
Methods have been renamed for clarity:
| V1 Method | V2 Method | Notes |
|---|---|---|
Collection:Insert() | Collection:InsertOne() | More explicit |
Collection:Update() | Collection:UpdateOne() | More explicit |
Collection:Delete() | Collection:DeleteOne() | More explicit |
Collection:Find() | Collection:Find() | Same |
V1 method names still work but are deprecated. Update your code to V2 methods for future compatibility.
Some methods return different values in V2:
InsertOne:
-- V1: Returns boolean
local success = collection:Insert(document)
-- V2: Returns document ID
local id = collection:InsertOne(document)
print("Inserted with ID:", id)
UpdateOne/UpdateMany:
-- V1: Returns boolean
local success = collection:Update(filter, update)
-- V2: Returns count of modified documents
local count = collection:UpdateOne(filter, update)
print("Updated", count, "documents")
DeleteOne/DeleteMany:
-- V1: Returns boolean
local success = collection:Delete(filter)
-- V2: Returns count of deleted documents
local count = collection:DeleteOne(filter)
print("Deleted", count, "documents")
V1:
local client = MongoDB.Client("mongodb://localhost:27017")
V2 (backward compatible):
-- Simple connection (same as V1)
local client = MongoDB.Client("mongodb://localhost:27017")
-- Or with options (new in V2)
local client = MongoDB.ClientWithOptions("mongodb://localhost:27017", {
app_name = "MyGModServer",
max_pool_size = 50,
retry_writes = true
})
garrysmod/lua/bin/Search your codebase for these patterns:
Find and Replace:
-- Find: collection:Insert(
-- Replace: collection:InsertOne(
-- Find: collection:Update(
-- Replace: collection:UpdateOne(
-- Find: collection:Delete(
-- Replace: collection:DeleteOne(
Before (V1):
local success = players:Insert({ name = "Player1" })
if success then
print("Insert successful")
end
After (V2):
local id = players:InsertOne({ name = "Player1" })
if id then
print("Insert successful, ID:", id)
end
Before deploying to production:
V1 Code:
local players = db:Collection("players")
-- Insert
local ok = players:Insert({ name = "John", score = 100 })
-- Find
local results = players:Find({ score = { ["$gt"] = 50 } })
-- Update
players:Update({ name = "John" }, { ["$set"] = { score = 150 } })
-- Delete
players:Delete({ name = "John" })
V2 Code:
local players = db:Collection("players")
-- Insert (returns ID)
local id = players:InsertOne({ name = "John", score = 100 })
print("Inserted with ID:", id)
-- Find (same, but can add limit)
local results = players:Find({ score = { ["$gt"] = 50 } }, 10)
-- Update (returns count)
local count = players:UpdateOne({ name = "John" }, { ["$set"] = { score = 150 } })
print("Updated", count, "documents")
-- Delete (returns count)
local count = players:DeleteOne({ name = "John" })
print("Deleted", count, "documents")
V1 Code:
function SavePlayer(ply)
local steamid = ply:SteamID()
local exists = players:Find({ steamid = steamid })
if #exists > 0 then
-- Update existing
players:Update(
{ steamid = steamid },
{ ["$set"] = { last_seen = os.time() } }
)
else
-- Insert new
players:Insert({
steamid = steamid,
name = ply:Nick(),
created_at = os.time()
})
end
end
V2 Code (with upsert):
function SavePlayer(ply)
local steamid = ply:SteamID()
-- Simpler: use upsert
players:UpdateOne(
{ steamid = steamid },
{
["$set"] = {
name = ply:Nick(),
last_seen = os.time()
},
["$setOnInsert"] = {
created_at = os.time(),
level = 1
}
},
true -- upsert: create if doesn't exist
)
end
V1 Code:
-- Insert multiple items (inefficient)
for _, item in ipairs(itemsToInsert) do
items:Insert(item)
end
-- Update multiple players (inefficient)
local activePlayers = players:Find({ active = true })
for _, player in ipairs(activePlayers) do
players:Update(
{ _id = player._id },
{ ["$inc"] = { credits = 100 } }
)
end
V2 Code (much faster):
-- Bulk insert
local ids = items:InsertMany(itemsToInsert)
print("Inserted", #ids, "items")
-- Bulk update
local count = players:UpdateMany(
{ active = true },
{ ["$inc"] = { credits = 100 } }
)
print("Updated", count, "players")
Take advantage of these new features:
-- InsertMany
local ids = players:InsertMany({
{ name = "Alice", level = 10 },
{ name = "Bob", level = 15 },
{ name = "Charlie", level = 20 }
})
-- UpdateMany
local count = players:UpdateMany(
{ level = { ["$lt"] = 10 } },
{ ["$inc"] = { level = 1 } }
)
-- DeleteMany
local count = logs:DeleteMany({
created_at = { ["$lt"] = os.time() - (30 * 24 * 60 * 60) }
})
-- Get statistics
local stats = players:Aggregate({
{
["$group"] = {
_id = "$rank",
count = { ["$sum"] = 1 },
avgLevel = { ["$avg"] = "$level" }
}
},
{
["$sort"] = { count = -1 }
}
})
-- Create indexes for better performance
players:CreateIndex({ steamid = 1 }, true, "steamid_unique")
players:CreateIndex({ level = -1, score = -1 }, false, "level_score")
-- List indexes
local indexes = players:ListIndexes()
-- Drop index
players:DropIndex("old_index")
-- Count matching documents
local total = players:Count({})
local active = players:Count({ active = true })
local vips = players:Count({ rank = "VIP" })
-- Find single document (more efficient than Find with limit)
local player = players:FindOne({ steamid = "STEAM_0:1:12345" })
-- List collections
local collections = db:ListCollections()
-- Get collection stats
local stats = db:Stats("players")
-- Drop database (careful!)
db:Drop()
If you need time to migrate, you can use V1 compatibility mode:
MongoDB.UseV2(false) -- Switch to V1 mode
-- Your old V1 code here
MongoDB.UseV2(true) -- Switch back to V2 mode
Compatibility mode is for transition only. Don't rely on it long-term. Plan to fully migrate to V2.
V2 offers significant performance improvements:
| Operation | V1 Performance | V2 Performance | Improvement |
|---|---|---|---|
| Insert 1000 docs (loop) | ~2000ms | ~2000ms | Same |
| Insert 1000 docs (bulk) | N/A | ~200ms | 10x faster |
| Update 100 docs (loop) | ~500ms | ~500ms | Same |
| Update 100 docs (bulk) | N/A | ~50ms | 10x faster |
| Query with index | ~50ms | ~20ms | 2.5x faster |
| Aggregation | N/A | ~30ms | New feature |
Problem: Using V2 methods but module is in V1 compatibility mode.
Solution:
MongoDB.UseV2(true) -- Enable V2 mode
Problem: V2 return values changed.
Solution: Update your code to handle new return types:
-- V1 code
if players:Insert(doc) then
print("Success")
end
-- V2 code
local id = players:InsertOne(doc)
if id then
print("Success, ID:", id)
end
Problem: Not using V2 features optimally.
Solution:
InsertMany, UpdateMany)FindOne instead of Find for single documentsFind queriesUse this checklist to track your migration:
garrysmod/lua/bin/Insert → InsertOne, etc.)If you encounter issues during migration: