Retrieve multiple documents matching a filter.
local documents = collection:Find(filter, limit)
Parameters:
filter (table): Query filterlimit (number, optional): Maximum documents to returnReturns:
table: Array of matching documentslocal players = db:Collection("players")
-- Find all players
local all = players:Find({})
-- Find with filter
local highLevel = players:Find({
level = { ["$gte"] = 10 }
})
-- Find with limit
local top10 = players:Find({}, 10)
-- Complex filter
local vips = players:Find({
rank = { ["$in"] = { "VIP", "Premium", "Ultimate" } },
active = true,
banned = { ["$ne"] = true }
}, 50)
-- Get active high-level players
local function GetVeteranPlayers()
local veterans = players:Find({
level = { ["$gte"] = 50 },
playtime = { ["$gte"] = 100 }, -- 100+ hours
banned = { ["$ne"] = true },
last_seen = { ["$gte"] = os.time() - (7 * 24 * 60 * 60) } -- Last 7 days
}, 20)
return veterans
end
-- Display veteran players
local vets = GetVeteranPlayers()
print("Veteran Players (" .. #vets .. "):")
for i, player in ipairs(vets) do
print(string.format("%d. %s - Level %d", i, player.username, player.level))
end
-- Show page 1
local page1 = players:Find({ active = true }, 20)
-- For page 2+, use aggregation with $skip
local page2 = players:Aggregate({
{ ["$match"] = { active = true } },
{ ["$skip"] = 20 },
{ ["$limit"] = 20 }
})
Retrieve a single document - more efficient than Find when you only need one result.
local document = collection:FindOne(filter)
Parameters:
filter (table): Query filterReturns:
table: The first matching document, or nil if not found-- Find by SteamID
local player = players:FindOne({
steamid = "STEAM_0:1:12345"
})
if player then
print("Found:", player.username)
print("Level:", player.level)
else
print("Player not found")
end
-- Find by multiple criteria
local admin = players:FindOne({
rank = "Admin",
active = true
})
-- Load player data when they join
hook.Add("PlayerInitialSpawn", "LoadPlayerData", function(ply)
local steamid = ply:SteamID()
local data = players:FindOne({ steamid = steamid })
if data then
-- Existing player
ply.PlayerData = data
ply:ChatPrint("Welcome back, " .. data.username .. "!")
ply:ChatPrint("Level: " .. data.level .. " | Credits: " .. data.credits)
-- Update last seen
players:UpdateOne(
{ steamid = steamid },
{ ["$set"] = { last_seen = os.time() } }
)
else
-- New player
print("New player detected:", ply:Nick())
end
end)
-- Check if item exists before purchase
local function CanPurchaseItem(itemId)
local item = shopItems:FindOne({ id = itemId })
if not item then
return false, "Item not found"
end
if item.stock ~= -1 and item.stock <= 0 then
return false, "Out of stock"
end
return true, item
end
Count documents matching a filter - faster than fetching all documents.
local count = collection:Count(filter)
Parameters:
filter (table): Query filterReturns:
number: Count of matching documents-- Count all players
local total = players:Count({})
print("Total players:", total)
-- Count active players
local active = players:Count({ active = true })
print("Active players:", active)
-- Count VIPs
local vipCount = players:Count({ rank = "VIP" })
print("VIP players:", vipCount)
-- Count high-level players
local veterans = players:Count({
level = { ["$gte"] = 50 }
})
print("Level 50+ players:", veterans)
-- Count players from last week
local weekAgo = os.time() - (7 * 24 * 60 * 60)
local recentPlayers = players:Count({
last_seen = { ["$gte"] = weekAgo }
})
print("Players this week:", recentPlayers)
-- Create admin command to show server statistics
concommand.Add("sv_stats", function(ply)
if not ply:IsAdmin() then return end
local total = players:Count({})
local active = players:Count({
last_seen = { ["$gte"] = os.time() - (7 * 24 * 60 * 60) }
})
local banned = players:Count({ banned = true })
local vips = players:Count({ rank = "VIP" })
ply:ChatPrint("=== SERVER STATISTICS ===")
ply:ChatPrint("Total Players: " .. total)
ply:ChatPrint("Active (7 days): " .. active)
ply:ChatPrint("VIP Members: " .. vips)
ply:ChatPrint("Banned: " .. banned)
end)
Use MongoDB's powerful query operators to filter documents:
-- Equal (implicit)
{ field = value }
-- Not equal
{ field = { ["$ne"] = value } }
-- Greater than
{ field = { ["$gt"] = value } }
-- Greater than or equal
{ field = { ["$gte"] = value } }
-- Less than
{ field = { ["$lt"] = value } }
-- Less than or equal
{ field = { ["$lte"] = value } }
-- In array
{ field = { ["$in"] = { value1, value2, value3 } } }
-- Not in array
{ field = { ["$nin"] = { value1, value2 } } }
-- AND (implicit - all conditions must match)
{
level = { ["$gte"] = 10 },
active = true,
banned = { ["$ne"] = true }
}
-- OR (any condition must match)
{
["$or"] = {
{ rank = "VIP" },
{ rank = "Premium" },
{ level = { ["$gte"] = 50 } }
}
}
-- Combined AND + OR
{
active = true, -- Must be active
["$or"] = { -- AND (VIP OR high level)
{ rank = "VIP" },
{ level = { ["$gte"] = 50 } }
}
}
-- Field exists
{ email = { ["$exists"] = true } }
-- Field doesn't exist
{ temp_data = { ["$exists"] = false } }
-- Type check
{ age = { ["$type"] = "number" } }
-- Regex pattern
{ username = { ["$regex"] = "^Player" } } -- Starts with "Player"
-- Case-insensitive search
{ username = { ["$regex"] = "admin", ["$options"] = "i" } }
-- Contains
{ bio = { ["$regex"] = "veteran" } }
local function GetPlayersByRank(rank)
return players:Find({ rank = rank })
end
-- Usage
local admins = GetPlayersByRank("Admin")
local vips = GetPlayersByRank("VIP")
-- Search players by username (case-insensitive)
local function SearchPlayers(query)
return players:Find({
username = { ["$regex"] = query, ["$options"] = "i" }
}, 10)
end
-- Usage
concommand.Add("findplayer", function(ply, cmd, args)
local query = args[1]
if not query then
ply:ChatPrint("Usage: findplayer <name>")
return
end
local results = SearchPlayers(query)
ply:ChatPrint("Found " .. #results .. " players:")
for i, p in ipairs(results) do
ply:ChatPrint(i .. ". " .. p.username .. " (Level " .. p.level .. ")")
end
end)
local function GetRecentTransactions(steamid, limit)
limit = limit or 10
return transactions:Aggregate({
{
["$match"] = { steamid = steamid }
},
{
["$sort"] = { created_at = -1 }
},
{
["$limit"] = limit
}
})
end
-- Find players who haven't logged in for 30 days
local function GetInactivePlayers()
local thirtyDaysAgo = os.time() - (30 * 24 * 60 * 60)
return players:Find({
last_seen = { ["$lt"] = thirtyDaysAgo },
banned = { ["$ne"] = true }
})
end
-- DON'T: Fetch all and filter in Lua
local all = players:Find({}) -- Fetches EVERYTHING
local filtered = {}
for _, p in ipairs(all) do
if p.level >= 10 then
table.insert(filtered, p)
end
end
-- DO: Filter in database
local filtered = players:Find({
level = { ["$gte"] = 10 }
}, 100) -- With limit