Blog with comments
app:get("/blog", function(ctx)
local result = api.dataset.find("posts", {
filter = { status = "published" },
order = "id_desc",
limit = 10
})
-- Attach comment counts to each post
for _, post in ipairs(result.items) do
local comments = api.dataset.find("comments", {
filter = { post_id = { eq = post.id } }
})
post.comment_count = comments.total
end
return ctx:render("blog", { posts = result.items })
end)
Product catalog with dynamic filters
app:get("/products", function(ctx)
local filter = { status = "active" }
if req.query.category then
filter.category = req.query.category
end
if req.query.min_price then
filter.price = { gte = tonumber(req.query.min_price) }
end
if req.query.max_price then
filter.price = filter.price or {}
filter.price.lte = tonumber(req.query.max_price)
end
if req.query.q then
filter.name = { like = "%" .. req.query.q .. "%" }
end
local result = api.dataset.find("products", {
filter = filter,
order = "price_asc",
limit = 20
})
return ctx:render("catalog", {
products = result.items,
total = result.total
})
end)
Contact form submissions
app:post("/contact", function(ctx)
local v = validator(req.post, {
name = "required|string|min:2",
email = "required|email",
message = "required|string|min:10"
})
if v:fails() then
ctx:flash("error", v:first())
return ctx:redirect("/contact")
end
local data = v:valid()
api.dataset.create("submissions", {
name = data.name,
email = data.email,
message = data.message,
ip = env.remote_ip,
created_at = os.date("!%Y-%m-%dT%H:%M:%SZ")
})
ctx:flash("success", "Thanks! We'll be in touch.")
return ctx:redirect("/contact")
end)
Page view tracking
app:on("after", function(ctx)
-- Skip API routes
if str.starts_with(req.path, "/api/") then
return
end
api.dataset.create("pageviews", {
path = req.path,
referrer = req.headers["referer"] or "direct",
ip = env.remote_ip,
timestamp = os.date("!%Y-%m-%dT%H:%M:%SZ")
})
end)
Admin stats dashboard
app:get("/admin/stats", function(ctx)
if not env.is_admin then
return ctx:error("Admin only", 403)
end
return ctx:render("admin_stats", {
total_posts = api.dataset.find("posts").total,
total_comments = api.dataset.find("comments").total,
total_submissions = api.dataset.find("submissions").total,
total_pageviews = api.dataset.find("pageviews").total,
recent_submissions = api.dataset.find("submissions", {
order = "id_desc", limit = 5
}).items
})
end)
Tip: Keep documents small and flat. Don't nest huge arrays inside documents — use separate collections and reference by ID. For heavy aggregation, pre-compute counters on write rather than counting on every read.