Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

Real-World Examples

```lua

On this page

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.

Previous Access Control Next Advanced Querying