Finders & Aggregations
Locate records by field values, compute aggregates, pluck specific columns, and perform atomic instance operations on your models.
Finder Methods
Finder methods provide convenient shortcuts for common lookup patterns. They return model instances (or null when no match is found).
FIND_BY Find by Exact Field Match
Returns the first record whose field equals the given value, or null if none is found.
# Find by exact field match
let user = User.find_by("email", "[email protected]")
FIRST_BY Find with Ordering
Returns the first record matching the field value, with ordering applied.
# Find with ordering (first by field value)
let user = User.first_by("name", "Alice")
FIND_OR_CREATE_BY Find or Create
Returns an existing record if one matches, or creates a new one. An optional third argument provides additional fields for creation.
# Find or create - returns existing or creates new
let user = User.find_or_create_by("email", "[email protected]")
let user = User.find_or_create_by("email", "[email protected]", { "name": "New User" })
Aggregations
Aggregation methods let you compute sums, averages, minimums, maximums, and grouped totals directly in the database.
QueryBuilder mode: Aggregation methods (sum, avg, min, max, group_by) return a QueryBuilder in aggregation mode. Chain with .first to execute and get the result, or .to_query to inspect the generated SDBQL.
SUM Sum
Compute the sum of a numeric field. Chain .first to execute.
# Sum — chain .first to execute
let total = User.where("age > @a", { "a": 18 }).sum("balance").first
AVG Average
# Average
let avg = User.avg("score").first
MIN Minimum
# Minimum
let min_score = User.min("score").first
MAX Maximum
# Maximum
let max_score = User.max("views").first
GROUP_BY Group By Aggregation
Group records by a field and apply an aggregation function. Chain .all for grouped results.
# Group by aggregation — chain .all for grouped results
let by_country = User.group_by("country", "sum", "balance").all
# Returns: [{ group: "US", result: 1000 }, { group: "FR", result: 500 }, ...]
INSPECT Inspecting Generated Queries
Use .to_query to see the SDBQL that a QueryBuilder will execute.
# Inspect the generated query
let q = User.where("active = @a", { "a": true }).sum("balance").to_query
# => FOR doc IN users FILTER doc.active == @a RETURN SUM(doc.balance)
Pluck
Use pluck to retrieve only specific field values instead of full model instances. This is more efficient when you only need a subset of fields.
SINGLE FIELD Pluck a Single Field
Returns a flat array of values. Chain .all to execute.
# Get array of single field values — chain .all to execute
let names = User.where("active = @a", { "a": true }).pluck("name").all
# Returns: ["Alice", "Bob", "Charlie"]
MULTIPLE FIELDS Pluck Multiple Fields
Returns an array of objects with the requested keys.
# Get multiple fields as objects
let users = User.pluck("name", "email").all
# Returns: [{ name: "Alice", email: "[email protected]" }, ...]
Exists
Check whether any records match a query without fetching them. Returns a boolean.
# Check if records exist — chain .first to execute (returns boolean)
let exists = User.where("role = @r", { "r": "admin" }).exists.first
# Returns: true or false
# Inspect the generated query
let q = User.where("role = @r", { "r": "admin" }).exists.to_query
# => FOR doc IN users FILTER doc.role == @r LIMIT 1 RETURN true
Instance Increment/Decrement
Perform atomic updates and utility operations on individual model instances.
INCREMENT / DECREMENT Atomic Field Updates
Atomically increment or decrement a numeric field in the database. The default step is 1.
let user = User.find("user_id")
# Atomic increment/decrement
user.increment("view_count") # +1
user.increment("view_count", 5) # +5
user.decrement("stock") # -1
TOUCH Update Timestamp
Updates the _updated_at timestamp without modifying any other fields.
# Update timestamp only
user.touch # Updates _updated_at
RELOAD Refresh from Database
Re-fetches the record from the database, discarding any unsaved local changes.
# Refresh from database
user.reload