Crud Operations

Common Patterns

CRUD best practices and design patterns

Upsert Pattern

Create or update in one operation:

players:UpdateOne(
    { steamid = steamid },
    {
        ["$set"] = { username = name, last_seen = os.time() },
        ["$setOnInsert"] = { created_at = os.time(), level = 1 }
    },
    true  -- upsert
)

Atomic Counter

-- Safe counter increment
stats:UpdateOne(
    { key = "page_views" },
    { ["$inc"] = { count = 1 } },
    true
)

Conditional Update

-- Purchase only if enough credits
local success = players:UpdateOne(
    {
        steamid = steamid,
        credits = { ["$gte"] = price }
    },
    {
        ["$inc"] = { credits = -price },
        ["$push"] = { purchases = itemId }
    }
)
return success > 0

Pagination

local function GetPage(pageNum, perPage)
    return players:Aggregate({
        { ["$sort"] = { level = -1 } },
        { ["$skip"] = (pageNum - 1) * perPage },
        { ["$limit"] = perPage }
    })
end

Soft Delete

-- Don't delete, mark as deleted
players:UpdateOne(
    { steamid = steamid },
    {
        ["$set"] = {
            deleted = true,
            deleted_at = os.time()
        }
    }
)
-- Query excluding deleted
players:Find({ deleted = { ["$ne"] = true } })

Best Practices

  • Use upsert for "create or update"
  • Use atomic operations ($inc, $push) instead of read-modify-write
  • Add timestamps (created_at, updated_at)
  • Use indexes on frequently queried fields
  • Always limit Find queries
  • Validate data before inserting
  • Use soft deletes for important data