Queries

July 10, 2026 ยท View on GitHub

The fluent QueryBuilder pushes conditions down to MongrelDB's native indexes for sub-millisecond lookups - bitmap, learned-range, FM-index full text, HNSW vector similarity, and more. Each condition type maps to one specialized index; conditions are AND-ed together.

mut q := db.query('orders')
q = q.where_('range', {
	'column': mongreldb.int_value(3)
	'min': mongreldb.float_value(100.0)
	'max': mongreldb.float_value(500.0)
})
q = q.projection([1, 2])
q = q.limit_(100)
rows := q.execute() or { panic(err) }

This guide covers every condition type, projection, limits, combining conditions, and the friendly aliases the builder translates for you.


The basics

Every query starts with db.query(table) and ends with execute:

MethodPurpose
where_(type, params)Add a native condition. Multiple where_ calls are AND-ed.
projection(column_ids)Return only these column ids (omit for all columns).
limit_(n)Cap the number of rows.
execute()Send and decode.

The request body produced by the builder matches the daemon's /kit/query shape:

{
  "table": "orders",
  "conditions": [{"range": {"column_id": 3, "lo": 100.0, "hi": 500.0}}],
  "projection": [1, 2],
  "limit": 100
}

Condition types

params is a map[string]json2.Any. Column references use the numeric column id, never the column name.

pk - exact primary-key match

mut q := db.query('orders')
q = q.where_('pk', {'value': mongreldb.int_value(42)})
_ = q.execute() or { panic(err) }

range - integer range (learned-range index)

Inclusive bounds. Omit lo (min) or hi (max) for an open range.

mut q := db.query('orders')
q = q.where_('range', {
	'column': mongreldb.int_value(3)
	'min': mongreldb.int_value(100)
	'max': mongreldb.int_value(500)
})
_ = q.execute() or { panic(err) }

range_f64 - float range with inclusive/exclusive control

mut q := db.query('orders')
q = q.where_('range_f64', {
	'column': mongreldb.int_value(3)
	'min': mongreldb.float_value(100.0)
	'max': mongreldb.float_value(500.0)
	'min_inclusive': mongreldb.bool_value(true)
	'max_inclusive': mongreldb.bool_value(false) // (100.0, 500.0]
})
_ = q.execute() or { panic(err) }

bitmap_eq - equality on a bitmap-indexed column

mut q := db.query('orders')
q = q.where_('bitmap_eq', {
	'column': mongreldb.int_value(2)
	'value': mongreldb.string_value('Alice')
})
_ = q.execute() or { panic(err) }

is_null / is_not_null - null checks

mut q := db.query('orders')
q = q.where_('is_null', {'column': mongreldb.int_value(3)})
_ = q.execute() or { panic(err) }

fm_contains - full-text substring search (FM-index)

Use pattern (the server key) or the friendly value alias - both translate to pattern on the wire for FTS conditions.

mut q := db.query('documents')
q = q.where_('fm_contains', {
	'column': mongreldb.int_value(2)
	'pattern': mongreldb.string_value('database performance')
})
q = q.limit_(10)
_ = q.execute() or { panic(err) }

ann - dense vector similarity (HNSW)

Approximate nearest-neighbors over a vector column. k is the result count.

mut q := db.query('embeddings')
q = q.where_('ann', {
	'column': mongreldb.int_value(2)
	'query': /* your vector value */
	'k': mongreldb.int_value(10)
})
_ = q.execute() or { panic(err) }

Projection (column selection)

projection([1, 2]) restricts the columns in each returned row. Omit the call for all columns.

mut q := db.query('orders')
q = q.where_('range', {'column': mongreldb.int_value(3), 'min': mongreldb.int_value(100)})
q = q.projection([1, 2])
_ = q.execute() or { panic(err) }

Limit

limit_(n) caps the result.

mut q := db.query('orders')
q = q.where_('range', {'column': mongreldb.int_value(3), 'min': mongreldb.int_value(100)})
q = q.limit_(100)
rows := q.execute() or { panic(err) }

Multiple AND conditions

Chain where_ calls. Every condition must match; the server intersects the index results.

mut q := db.query('orders')
q = q.where_('bitmap_eq', {
	'column': mongreldb.int_value(2)
	'value': mongreldb.string_value('Alice')
})
q = q.where_('range', {
	'column': mongreldb.int_value(3)
	'min': mongreldb.int_value(100)
	'max': mongreldb.int_value(500)
})
q = q.projection([1, 3])
q = q.limit_(50)
_ = q.execute() or { panic(err) }

Friendly alias translation

You writeSent asApplies to
columncolumn_idall condition types
minlorange, range_f64
maxhirange, range_f64
min_inclusivelo_inclusiverange_f64
max_inclusivehi_inclusiverange_f64
valuepatternfm_contains, fm_contains_all only

For arbitrary predicates, joins, and aggregations that the native indexes do not cover, use SQL instead - see sql.md.