Contents
SDBQL Pro Tip
Use RETURN MERGE(doc, { field: "value" }) to add fields to result documents without modifying them in the database.
SDBQL Reference
Master the SoliDB Query Language (SDBQL) in SoliDB. A powerful, declarative language for querying and manipulating your JSON documents.
Basic Syntax
SDBQL queries follow a declarative structure that reads like a sentence.
LET variable = expression
FOR variable IN collection
FILTER expression
SORT field [ASC|DESC]
LIMIT [offset,] count
RETURN expression
LET Variable Assignment
Binds values or subquery results to variables.
FOR Iteration
Iterates over collections or arrays.
FILTER Filtering
Restricts results based on conditions.
RETURN Projection
Constructs the result documents.
.. Range Expressions
Create numeric arrays using the range operator
start..end (inclusive on
both ends).
1..5 → [1, 2, 3, 4,
5]
Basic Range
-- Returns [1, 2, 3, 4, 5]
RETURN 1..5
-- Negative numbers
RETURN -2..2 // [-2, -1, 0, 1, 2]
In FOR Loop
FOR i IN 1..10
RETURN i * 2
-- With expressions
LET n = 5
FOR i IN 1..n
RETURN i
Batch Insert with Range
FOR i IN 1..100
INSERT { index: i, name: CONCAT("Item", i) } INTO items
RETURN i
LET & Subqueries
Correlated Subqueries
Use LET inside a FOR loop to perform
powerful joins and aggregations.
FOR u IN users
-- Subquery accessing outer variable 'u'
LET userOrders = (
FOR o IN orders
FILTER o.user == u.name
RETURN o
)
RETURN { name: u.name, orders: userOrders }
Aggregation with Subqueries
FOR u IN users
LET totalSpent = SUM((
FOR o IN orders
FILTER o.user == u.name
RETURN o.amount
))
FILTER totalSpent > 100
RETURN { name: u.name, spent: totalSpent }
Operators
Comparison
Logical
Arithmetic
Bind Variables
SECURITY ESSENTIALPrevent Injection Attacks
Never concatenate user input directly into query strings.
Always use bind variables (@variable) to safely
substitute values.
Query
FOR u IN users
FILTER u.name == @name
AND u.age >= @minAge
RETURN u
Bind Vars
{
"name": "Alice",
"minAge": 25
}
Dynamic Field Access
Use bracket notation with bind variables for dynamic field names.
FILTER doc[@fieldName] == @value
Data Modification
SDBQL supports data modification operations for inserting and updating documents directly within queries.
INSERT Insert Documents
Insert new documents into a collection.
INSERT document INTO
collection
Simple Insert
LET nums = [1, 2, 3]
FOR i IN nums
INSERT { value: i } INTO items
RETURN i
With Computed Fields
FOR i IN 1..5
INSERT {
name: CONCAT("User", i),
index: i
} INTO users
RETURN i
UPDATE Update Documents
Update existing documents in a collection by merging changes into existing fields.
UPDATE document WITH
{ changes } IN
collection
Merge Behavior
UPDATE merges the changes into the existing document. Fields not specified in the changes object are preserved.
Update Single Document
FOR doc IN users
FILTER doc.name == "Alice"
UPDATE doc WITH {
status: "premium"
} IN users
RETURN doc.name
Update Multiple Fields
FOR doc IN users
FILTER doc.age >= 30
UPDATE doc WITH {
status: "vip",
level: 5,
verified: true
} IN users
RETURN doc._key
With Computed Values
FOR doc IN users
FILTER doc.city == "Paris"
UPDATE doc WITH {
fullName: CONCAT(doc.name, " from ", doc.city),
region: "Europe"
} IN users
RETURN doc.name
With Bind Variables
FOR doc IN users
FILTER doc.name == @name
UPDATE doc WITH { points: @points } IN users
RETURN doc.name
{
"name": "Alice",
"points": 100
}
REMOVE Delete Documents
Remove documents from a collection.
REMOVE document IN
collection
Caution
REMOVE permanently deletes documents. Always use FILTER to target specific documents, or you'll delete all documents in the collection.
Remove by Key (Single)
FOR doc IN users
FILTER doc._key == "alice"
REMOVE doc IN users
RETURN doc._key
Remove by Condition (Multiple)
FOR doc IN users
FILTER doc.city == "Paris"
REMOVE doc IN users
RETURN doc.name
Remove All (Use with Caution!)
FOR doc IN users
REMOVE doc IN users
RETURN doc._key
Graph Queries
SoliDB supports native graph traversals and shortest path algorithms using dedicated keywords.
TRAVERSAL Graph Traversal
Traverse the graph starting from a vertex.
FOR vertex[,
edge] IN [min..max]
DIRECTION
startVertex
edgeCollection
_from → _to
_to ← _from
Either direction
Direct (1 Hop)
FOR v IN OUTBOUND "users/alice" follows
RETURN v.name
Variable Depth (1..2 Hops)
FOR v, e IN 1..2 ANY "users/alice" follows
RETURN { user: v.name, type: e.type }
SHORTEST_PATH Shortest Path
Find the shortest path between two vertices.
FOR vertex[,
edge] IN
SHORTEST_PATH
start TO
end
DIRECTION
edgeCollection
Find Path
FOR v, e IN OUTBOUND SHORTEST_PATH
"users/alice" TO "users/charlie"
follows
RETURN { vertex: v.name, edge: e }
Functions
Numeric
ABS(number)
Returns the absolute value.
RETURN ABS(-5) // 5
CEIL(number)
Rounds up to nearest integer.
RETURN CEIL(4.2) // 5
FLOOR(number)
Rounds down to nearest integer.
RETURN FLOOR(4.8) // 4
ROUND(num, prec?)
Rounds to specified precision.
RETURN ROUND(3.14159, 2) // 3.14
RANDOM()
Returns a random float between 0 and 1.
RETURN RANDOM() // 0.54321...
String
CONCAT(str1, ...)
Concatenates strings.
RETURN CONCAT("A", "B") // "AB"
CONCAT_SEPARATOR(sep, arr)
Joins array with separator.
RETURN CONCAT_SEPARATOR(",", ["A","B"])
LENGTH(str)
Returns string length.
RETURN LENGTH("Hello") // 5
SUBSTRING(str, start, len?)
Extracts substring.
RETURN SUBSTRING("Hello", 0, 2) // "He"
LOWER(str) / UPPER(str)
Case conversion.
RETURN LOWER("Hi") // "hi"
LEVENSHTEIN(s1, s2)
Calculates edit distance.
RETURN LEVENSHTEIN("foo", "bar")
REGEX_REPLACE(text, pattern, replacement,
caseInsensitive?)
Replace occurrences of a pattern in a string.
RETURN REGEX_REPLACE("the quick brown fox", "the (.*) fox", "a $1 dog")
// "a quick brown dog"
CONTAINS(text, search, returnIndex?)
Checks if search string is in text. Returns boolean or index.
RETURN CONTAINS("foobar", "bar") // true
RETURN CONTAINS("foobar", "bar", true) // 3
SUBSTITUTE(val, search, replace, limit?)
Replaces occurrences of search with replace.
RETURN SUBSTITUTE("foobar", "foo", "baz") // "bazbar"
RETURN SUBSTITUTE("banana", "a", "o", 2) // "bonona"
RETURN SUBSTITUTE("hello", {"l": "x", "o": "y"}) // "hexxiy"
SPLIT(val, sep, limit?)
Splits string into array.
RETURN SPLIT("foo-bar-baz", "-") // ["foo", "bar", "baz"]
RETURN SPLIT("foo-bar-baz", "-", 2) // ["foo", "bar-baz"]
RETURN SPLIT("foo-bar-baz", "-", -2) // ["foo-bar", "baz"]
TRIM(val, type?/chars?)
Trims whitespace or chars. type: 0=both, 1=left, 2=right.
RETURN TRIM(" foo ") // "foo"
RETURN TRIM(" foo ", 1) // "foo "
RETURN TRIM("--foo--", "-") // "foo"
LTRIM(val, chars?)
Trims from start.
RETURN LTRIM(" foo ") // "foo "
RTRIM(val, chars?)
Trims from end.
RETURN RTRIM(" foo ") // " foo"
JSON_PARSE(text)
Parses JSON string to value. Returns NULL on error.
RETURN JSON_PARSE("{\"a\":1}") // {a: 1}
JSON_STRINGIFY(value)
Serializes value to JSON string.
RETURN JSON_STRINGIFY({a: 1}) // "{\"a\":1}"
Type Casting Functions
TO_BOOL(value)
Casts value to boolean.
RETURN TO_BOOL(null) // false
RETURN TO_BOOL(1) // true
RETURN TO_BOOL(0) // false
TO_NUMBER(value)
Casts value to number.
RETURN TO_NUMBER("123") // 123
RETURN TO_NUMBER(true) // 1
RETURN TO_NUMBER("foo") // 0
TO_STRING(value)
Casts value to string.
RETURN TO_STRING(123) // "123"
RETURN TO_STRING(true) // "true"
RETURN TO_STRING(null) // ""
TO_ARRAY(value)
Casts value to array.
RETURN TO_ARRAY(null) // []
RETURN TO_ARRAY("foo") // ["foo"]
RETURN TO_ARRAY({a:1}) // [1]
Date
DATE_NOW()
Returns current Unix timestamp (ms).
RETURN DATE_NOW() // 1733234387000
DATE_ISO8601(timestamp)
Converts timestamp to ISO 8601 string.
RETURN DATE_ISO8601(1733234387000)
// "2025-12-03T13:59:47.000Z"
DATE_TIMESTAMP(date)
Converts ISO 8601 string to timestamp (ms).
RETURN DATE_TIMESTAMP("2025-12-03T13:59:47.000Z")
// 1764770387000
DATE_ISOWEEK(date)
Returns ISO 8601 week number (1-53).
RETURN DATE_ISOWEEK("2025-06-15T14:30:45Z")
// 24
DATE_DAYOFYEAR(date, tz?)
Returns day of year (1-366). Optional timezone.
RETURN DATE_DAYOFYEAR("2025-06-15T14:30:45Z")
// 166
DATE_DAYS_IN_MONTH(date, tz?)
Returns days in the month (28-31). Optional timezone.
RETURN DATE_DAYS_IN_MONTH("2024-02-15T00:00:00Z")
// 29 (leap year)
DATE_TRUNC(date, unit, timezone?)
Truncates date to specified unit. Returns ISO 8601 string.
Parameters
-
date- timestamp (ms) or ISO 8601 string -
unit- y/year, m/month, d/day, h/hour, i/minute, s/second, f/millisecond -
timezone- optional IANA timezone (e.g. "America/New_York")
Examples
DATE_TRUNC("2025-06-15T14:30:45Z", "day")
// "2025-06-15T00:00:00.000Z"
DATE_TRUNC("2025-06-15T20:30:00Z", "day", "America/New_York")
// "2025-06-15T04:00:00.000Z"
DATE_FORMAT(date, format, timezone?)
Formats date according to format string (strftime-style).
Format Specifiers
%Y - year (2025)
%m - month (01-12)
%d - day (01-31)
%H - hour 24h
(00-23)
%M - minute
(00-59)
%S - second
(00-59)
%I - hour 12h
(01-12)
%p - AM/PM
%A - weekday
(Sunday)
%B - month (June)
%j - day of year
%V - ISO week
Examples
DATE_FORMAT("2025-06-15T14:30:45Z", "%Y-%m-%d")
// "2025-06-15"
DATE_FORMAT("2025-06-15T14:30:45Z", "%I:%M %p")
// "02:30 PM"
DATE_FORMAT("2025-06-15T14:30:00Z", "%H:%M", "America/New_York")
// "10:30"
DATE_ADD(date, amount, unit, timezone?)
Add or subtract a specified amount of time to/from a date. Returns ISO 8601 string.
Parameters
-
date- timestamp (ms) or ISO 8601 string -
amount- number to add (positive) or subtract (negative) -
unit- y/year, m/month, w/week, d/day, h/hour, i/minute, s/second, f/millisecond -
timezone- optional IANA timezone (e.g. "America/New_York")
Examples
DATE_ADD("2025-06-15T14:30:45Z", 3, "months")
// "2025-09-15T14:30:45.000Z"
DATE_ADD("2025-06-15T14:30:45Z", -7, "days")
// "2025-06-08T14:30:45.000Z"
DATE_ADD(1733234387000, 2, "hours")
// "2024-12-03T15:59:47.000Z"
DATE_SUBTRACT(date, amount, unit, timezone?)
Subtract a specified amount of time from a date. Convenience wrapper for DATE_ADD with negated amount. Returns ISO 8601 string.
Parameters
-
date- timestamp (ms) or ISO 8601 string -
amount- number to subtract (always positive) -
unit- y/year, m/month, w/week, d/day, h/hour, i/minute, s/second, f/millisecond -
timezone- optional IANA timezone (e.g. "America/New_York")
Examples
DATE_SUBTRACT("2025-06-15T14:30:45Z", 7, "days")
// "2025-06-08T14:30:45.000Z"
DATE_SUBTRACT("2025-06-15T14:30:45Z", 3, "months")
// "2025-03-15T14:30:45.000Z"
DATE_SUBTRACT(1733234387000, 1, "day")
// "2024-12-02T13:59:47.000Z"
DATE_DIFF(date1, date2, unit, asFloat?, timezone1?,
timezone2?)
Calculate the difference between two dates in a given time unit. Returns negative if date2 is before date1.
Parameters
-
date1- timestamp (ms) or ISO 8601 string -
date2- timestamp (ms) or ISO 8601 string -
unit- y/year, m/month, w/week, d/day, h/hour, i/minute, s/second, f/millisecond -
asFloat- optional, preserve decimal places (default: false) -
timezone1- optional IANA timezone for date1 -
timezone2- optional IANA timezone for date2
Examples
DATE_DIFF("2025-06-01T00:00:00Z", "2025-06-11T00:00:00Z", "days")
// 10
DATE_DIFF("2025-06-15T00:00:00Z", "2025-06-15T12:00:00Z", "days", true)
// 0.5
DATE_DIFF("2025-06-15T00:00:00Z", "2025-06-10T00:00:00Z", "days")
// -5 (negative: date2 before date1)
Geospatial
DISTANCE(lat1, lon1, lat2, lon2)
Distance in meters between coordinates.
GEO_DISTANCE(p1, p2)
Distance in meters between GeoPoints.
Fulltext Search
FULLTEXT(col, field, query, dist?)
Fuzzy search using n-gram indexing.
LET matches = FULLTEXT("articles", "title", "rust", 2)
FOR m IN matches RETURN m.doc
BM25(field, query)
BM25 relevance scoring for ranking search results. Returns a numeric score that can be used in SORT clauses.
BM25 Algorithm
BM25 (Best Matching 25) is a probabilistic ranking function that provides more sophisticated relevance scoring than n-gram similarity. It considers term frequency, document length, and inverse document frequency.
Basic Scoring
FOR doc IN articles
RETURN {
title: doc.title,
score: BM25(doc.content, "machine learning")
}
Sort by Relevance
FOR doc IN articles
SORT BM25(doc.content, "rust database") DESC
LIMIT 10
RETURN doc
Combined with Filters
FOR doc IN articles
FILTER doc.published == true
SORT BM25(doc.content, "query optimization") DESC
LIMIT 5
RETURN {title: doc.title, score: BM25(doc.content, "query optimization")}
Aggregation
Basic Aggregations
SUM(arr)
Sum of all values in the array.
RETURN SUM([1, 2, 3, 4]) // 10
AVG(arr)
Average of all values.
RETURN AVG([1, 2, 3, 4]) // 2.5
MIN(arr)
Smallest value in the array.
RETURN MIN([5, 1, 9]) // 1
MAX(arr)
Largest value in the array.
RETURN MAX([5, 1, 9]) // 9
COUNT(arr)
Number of elements in the array.
RETURN COUNT([1, 2, 3]) // 3
COUNT_DISTINCT(arr)
Number of unique elements.
RETURN COUNT_DISTINCT([1, 2, 2, 3]) // 3
MEDIAN(arr)
Median value of the array.
RETURN MEDIAN([1, 5, 10]) // 5
PERCENTILE(arr, p)
Returns the p-th percentile (0-100).
RETURN PERCENTILE([1..100], 95) // 95
Statistical Functions
VARIANCE(arr)
Population variance.
RETURN VARIANCE([1, 2, 3, 4, 5]) // 2
VARIANCE_SAMPLE(arr)
Sample variance.
RETURN VARIANCE_SAMPLE([1, 2, 3, 4, 5]) // 2.5
STDDEV(arr)
Sample standard deviation.
RETURN STDDEV([1, 2, 3, 4, 5]) // 1.581...
STDDEV_POPULATION(arr)
Population standard deviation.
RETURN STDDEV_POPULATION([1, 2, 3, 4, 5]) // 1.414...
Aggregation Example
FOR u IN users
LET amounts = (FOR o IN orders FILTER o.user == u._key RETURN o.amount)
RETURN {
user: u.name,
total: SUM(amounts),
avg: ROUND(AVG(amounts), 2),
count: COUNT(amounts),
median: MEDIAN(amounts),
stddev: ROUND(STDDEV(amounts), 2)
}
Array
Access Functions
Access Functions
FIRST(arr)
Returns the first element.
RETURN FIRST([5, 1, 9]) // 5
COLLECTION_COUNT(coll)
Returns the number of documents in a collection.
RETURN COLLECTION_COUNT("users") // 100
LAST(arr)
Returns the last element.
RETURN LAST([5, 1, 9]) // 9
NTH(arr, n)
Returns element at index n (0-based).
RETURN NTH([5, 1, 9], 1) // 1
SLICE(arr, start, len?)
Extracts a portion of the array.
RETURN SLICE([1, 2, 3, 4, 5], 1, 3) // [2, 3, 4]
Transformation Functions
UNIQUE(arr)
Removes duplicate values.
RETURN UNIQUE([1, 2, 2, 3]) // [1, 2, 3]
SORTED(arr)
Sorts the array in ascending order.
RETURN SORTED([3, 1, 2]) // [1, 2, 3]
SORTED_UNIQUE(arr)
Sorts and removes duplicates.
RETURN SORTED_UNIQUE([3, 1, 2, 2]) // [1, 2, 3]
REVERSE(arr)
Reverses the array order.
RETURN REVERSE([1, 2, 3]) // [3, 2, 1]
FLATTEN(arr, depth?)
Flattens nested arrays. Depth defaults to 1.
RETURN FLATTEN([[1, 2], [3]], 1) // [1, 2, 3]
Combination Functions
PUSH(arr, elem)
Appends an element to the array.
RETURN PUSH([1, 2], 3) // [1, 2, 3]
APPEND(arr1, arr2)
Concatenates two arrays.
RETURN APPEND([1], [2, 3]) // [1, 2, 3]
UNION(arr1, arr2)
Union of arrays (produces unique values).
RETURN UNION([1, 2], [2, 3]) // [1, 2, 3]
INTERSECTION(arr1, arr2...)
Returns common elements between arrays.
RETURN INTERSECTION([1, 2], [2, 3]) // [2]
MINUS(arr1, arr2)
Returns elements in arr1 not in arr2.
RETURN MINUS([1, 2, 3], [2]) // [1, 3]
Search Functions
POSITION(arr, elem)
Returns true if element exists, false otherwise.
RETURN POSITION([10, 20], 20) // true
CONTAINS_ARRAY(arr, elem)
Legacy alias for POSITION.
RETURN CONTAINS_ARRAY([1, 2], 3) // false
Array Examples
-- Combine and deduplicate tags
LET tags1 = ["rust", "database"]
LET tags2 = ["database", "nosql"]
RETURN UNION(tags1, tags2) -- ["rust", "database", "nosql"]
-- Get top 3 values from sorted array
LET values = [5, 2, 8, 1, 9, 3]
RETURN SLICE(SORTED(values), 3, 3) -- [5, 8, 9] (last 3)
-- Flatten nested arrays
LET nested = [[1, 2], [3, [4, 5]]]
RETURN FLATTEN(nested, 2) -- [1, 2, 3, 4, 5]
Object & Array
MERGE(obj1, obj2)
Shallow merge of objects.
RETURN MERGE({a:1}, {b:2})
LENGTH(val)
Count elements in array/object.
RETURN LENGTH([1,2,3]) // 3
HAS(doc, attr)
Checks if document contains attribute.
FILTER HAS(doc, "email")
KEEP(doc, attr...)
Keep only specified attributes.
RETURN KEEP(doc, "name", "email")
ATTRIBUTES(doc, removeInternal?, sort?)
Top-level attribute keys of the document.
RETURN ATTRIBUTES(doc, true)
VALUES(doc, removeInternal?)
Returns top-level attribute values.
RETURN VALUES(doc, true)
UNSET(doc, attr...)
Removes specified attributes.
RETURN UNSET(doc, "password")
Miscellaneous
UUIDV4()
Generates a random v4 UUID.
RETURN UUIDV4() // "c4d3..."
UUIDV7()
Generates a time-ordered v7 UUID.
RETURN UUIDV7() // "018..."
Collection
COLLECTION_COUNT(name)
Returns the number of documents in a collection. Efficient metadata lookup without iterating documents.
RETURN COLLECTION_COUNT("users") // 42
Usage Example
Get document counts for multiple collections:
RETURN {
users: COLLECTION_COUNT("users"),
orders: COLLECTION_COUNT("orders"),
products: COLLECTION_COUNT("products")
}