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.

Advanced Querying

Dataset supports 13 comparison operators for precise queries. All operators work at any nesting level — combine them freely.

On this page

The complete operator reference

Dataset supports 13 comparison operators for precise queries. All operators work at any nesting level — combine them freely.

All operators

Operator Meaning Example
eq Equal (default, can omit) { status = "active" }
neq Not equal { status = { neq = "deleted" } }
gt Greater than { price = { gt = 100 } }
gte Greater than or equal { stock = { gte = 1 } }
lt Less than { score = { lt = 50 } }
lte Less than or equal { age = { lte = 65 } }
in Value in array { role = { in = { "admin", "editor" } } }
nin Value not in array { status = { nin = { "banned", "deleted" } } }
regex Lua pattern match { name = { regex = "^[A-Z]" } }
like SQL LIKE with % wildcards { title = { like = "%lua%" } }
contains JSON_CONTAINS (array membership) { tags = { contains = "sale" } }
null Field is null { deleted_at = { null = true } }
exists Field exists { email = { exists = true } }

Multiple operators on one field

-- Price range: $10 to $100
{ price = { gte = 10, lte = 100 } }

-- Status not deleted AND role in list
{
    status = { neq = "deleted" },
    role = { in = { "admin", "editor" } }
}

Compound filters (AND)

Multiple filter fields are AND-ed together automatically:

-- Active products, in stock, priced under $50
api.dataset.find("products", {
    filter = {
        status = "active",
        stock = { gt = 0 },
        price = { lt = 50 }
    }
})

OR logic

Use the or key for "any of these conditions match":

-- Posts that are either featured OR have high views
api.dataset.find("posts", {
    filter = {
        or = {
            { featured = true },
            { views = { gte = 1000 } }
        },
        status = "published"  -- AND with the OR group
    }
})

-- Products on sale OR new arrivals
api.dataset.find("products", {
    filter = {
        or = {
            { tags = { contains = "sale" } },
            { tags = { contains = "new" } }
        }
    }
})

Sorting

-- Sort by price, cheapest first
{ order = "price_asc" }

-- Sort by creation date, newest first
{ order = "id_desc" }

-- Sort by name alphabetically
{ order = "name_asc" }

Common sort fields: id_asc, id_desc, created_at_asc, created_at_desc, plus any field in your data with _asc or _desc.

Pagination

-- Page 2, 25 items per page
api.dataset.find("posts", {
    page = 2,
    limit = 25
})

-- Check if there are more pages
local result = api.dataset.find("posts", { page = 1, limit = 20 })
if result.total > 20 then
    -- there's a page 2
end

Search

-- Full-text search across document data
api.dataset.find("articles", {
    search = "lua framework"
})

Collections

-- List all collections
local names = api.dataset.collections()
for _, name in ipairs(names) do
    local count = api.dataset.find(name).total
    print(name .. ": " .. count .. " documents")
end

-- Purge an entire collection (admin only, permanent)
api.dataset.purge_collection("temp_logs")

Real-world patterns

Product catalog with filters

app:get("/products", function(ctx)
    local filter = { status = "active" }
    local order = "id_desc"

    -- Apply user-selected filters
    if req.query.min_price then
        filter.price = filter.price or {}
        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.cat then
        filter.category = req.query.cat
    end
    if req.query.sort == "price" then
        order = "price_asc"
    elseif req.query.sort == "newest" then
        order = "id_desc"
    end

    local result = api.dataset.find("products", {
        filter = filter,
        order = order,
        page = tonumber(req.query.page) or 1,
        limit = 12
    })

    return ctx:render("products", {
        products = result.items,
        total = result.total
    })
end)

User dashboard with stats

app:get("/admin/dashboard", function(ctx)
    local total_users = api.users.stats()
    local total_posts = api.dataset.find("posts", {
        filter = { status = "published" }
    }).total
    local total_orders = api.dataset.find("orders").total
    local recent_users = api.users.list({ limit = 5, order = "id_desc" })

    return ctx:render("admin_dashboard", {
        stats = {
            users = total_users,
            posts = total_posts,
            orders = total_orders
        },
        recent_users = recent_users.items
    })
end)

Next: Access Control — control who can read and write each collection.

Previous Real-World Examples