CRUD Operations

Query Operations

Find and retrieve documents from MongoDB

Query Operations

Learn how to find and retrieve documents from MongoDB collections.

Find

Retrieve multiple documents matching a filter.

Syntax

local documents = collection:Find(filter [, limit])

Parameters

  • filter (table): Query filter (empty {} for all documents)
  • limit (number, optional): Maximum number of documents to return

Returns

  • table: Array of matching documents
  • nil: On failure

Examples

local players = db:Collection("players")

-- Find all documents
local allPlayers = players:Find({})
print("Total players:", #allPlayers)

-- Find with filter
local highLevel = players:Find({
    level = { ["$gte"] = 10 }
})

-- Find with limit
local topPlayers = players:Find(
    { level = { ["$gte"] = 5 } },
    10  -- Return max 10 documents
)

-- Iterate results
for i, player in ipairs(allPlayers) do
    print(player.username, "- Level", player.level)
end

FindOne

Retrieve the first document matching a filter.

Syntax

local document = collection:FindOne(filter)

Parameters

  • filter (table): Query filter

Returns

  • table: First matching document
  • nil: If not found or on failure

Examples

local players = db:Collection("players")

-- Find by unique field
local player = players:FindOne({
    steamid = "STEAM_0:1:12345678"
})

if player then
    print("Found:", player.username)
    print("Level:", player.level)
    print("Credits:", player.credits)
else
    print("Player not found")
end

-- Find by multiple criteria
local vipPlayer = players:FindOne({
    level = { ["$gte"] = 50 },
    vip = true
})

Count

Count documents matching a filter.

Syntax

local count = collection:Count(filter)

Parameters

  • filter (table): Query filter (empty {} for all documents)

Returns

  • number: Count of matching documents

Examples

local players = db:Collection("players")

-- Count all documents
local totalPlayers = players:Count({})
print("Total players:", totalPlayers)

-- Count with filter
local activePlayers = players:Count({
    last_login = { ["$gte"] = os.time() - (7 * 24 * 60 * 60) }
})
print("Active players (7 days):", activePlayers)

-- Count by criteria
local vipCount = players:Count({ vip = true })
local warriorCount = players:Count({ class = "Warrior" })

Query Filters

Empty Filter (All Documents)

-- Get all documents
local all = collection:Find({})

Equality

-- Exact match
local warriors = players:Find({ class = "Warrior" })

-- Match specific value
local level10 = players:Find({ level = 10 })

Comparison Operators

-- Greater than
local high = players:Find({ level = { ["$gt"] = 10 } })

-- Greater than or equal
local medium = players:Find({ level = { ["$gte"] = 5 } })

-- Less than
local low = players:Find({ level = { ["$lt"] = 5 } })

-- Less than or equal
local starter = players:Find({ level = { ["$lte"] = 3 } })

-- Not equal
local notBanned = players:Find({ banned = { ["$ne"] = true } })

-- Range (combined)
local midRange = players:Find({
    level = { ["$gte"] = 10, ["$lte"] = 20 }
})

Array Operators

-- Value in array
local specific = players:Find({
    class = { ["$in"] = { "Warrior", "Mage", "Rogue" } }
})

-- Value not in array
local nonCombat = players:Find({
    class = { ["$nin"] = { "Warrior", "Mage", "Rogue" } }
})

Logical Operators

-- AND (implicit with multiple fields)
local vipWarriors = players:Find({
    class = "Warrior",
    vip = true
})

-- OR
local highRank = players:Find({
    ["$or"] = {
        { level = { ["$gte"] = 50 } },
        { vip = true }
    }
})

-- AND with OR
local complexQuery = players:Find({
    class = "Warrior",
    ["$or"] = {
        { level = { ["$gte"] = 20 } },
        { experience = { ["$gte"] = 10000 } }
    }
})

Existence Check

-- Field exists
local hasInventory = players:Find({
    inventory = { ["$exists"] = true }
})

-- Field doesn't exist
local noInventory = players:Find({
    inventory = { ["$exists"] = false }
})

Async Query Operations

FindAsync

collection:FindAsync(filter, limit, callback)
limit is required and must be passed between the filter and the callback. If you skip it, your callback will receive no documents and will appear to not fire. Pass the maximum number of documents you want back (e.g. 100).
collection:FindAsync({ level = { ["$gte"] = 10 } }, 100, function(err, results)
    if err then
        print("Query error:", err)
        return
    end

    print("Found", #results, "players")
    for _, player in ipairs(results) do
        print("  " .. player.username)
    end
end)

FindOneAsync

collection:FindOneAsync({ steamid = "STEAM_0:1:12345" }, function(err, player)
    if err then
        print("Query error:", err)
        return
    end

    if player then
        print("Found:", player.username)
    else
        print("Player not found")
    end
end)

CountAsync

collection:CountAsync({ active = true }, function(err, count)
    if err then
        print("Count error:", err)
        return
    end

    print("Active players:", count)
end)

Practical Examples

Player Lookup

function GetPlayer(steamid)
    local players = db:Collection("players")
    return players:FindOne({ steamid = steamid })
end

function GetPlayerAsync(steamid, callback)
    local players = db:Collection("players")
    players:FindOneAsync({ steamid = steamid }, function(err, player)
        if err then
            callback(nil, err)
        else
            callback(player, nil)
        end
    end)
end

Leaderboard

function GetTopPlayers(limit)
    local players = db:Collection("players")

    -- Note: For sorted results, use Aggregate
    local results = players:Find(
        { banned = { ["$ne"] = true } },
        limit or 10
    )

    return results
end

Search Players

function SearchPlayers(criteria)
    local players = db:Collection("players")
    local filter = {}

    if criteria.minLevel then
        filter.level = filter.level or {}
        filter.level["$gte"] = criteria.minLevel
    end

    if criteria.maxLevel then
        filter.level = filter.level or {}
        filter.level["$lte"] = criteria.maxLevel
    end

    if criteria.class then
        filter.class = criteria.class
    end

    if criteria.vipOnly then
        filter.vip = true
    end

    return players:Find(filter, criteria.limit or 100)
end

-- Usage
local results = SearchPlayers({
    minLevel = 10,
    class = "Warrior",
    limit = 50
})

Online Player Check

function GetOnlinePlayers(steamids)
    local players = db:Collection("players")

    return players:Find({
        steamid = { ["$in"] = steamids }
    })
end

-- Usage
local online = GetOnlinePlayers({
    "STEAM_0:1:11111",
    "STEAM_0:1:22222",
    "STEAM_0:1:33333"
})

Best Practices

  1. Use FindOne when expecting single result: More efficient than Find
  2. Add limits to Find: Prevent memory issues with large collections
  3. Use indexes: Create indexes on frequently queried fields
  4. Use async for gameplay: Avoid blocking during game logic
  5. Check for nil: Always handle not-found cases

Next Steps