Queries
This page covers the filtering and relation-modification vocabulary that builds on the basics in Relations. Everything here returns a new relation — the original is never mutated.
where shorthands
where(%conditions) accepts several value shapes:
| Shape | SQL emitted |
|---|---|
where({col => $value}) |
col = ? |
where({col => Nil}) |
col IS NULL |
where({col => [a, b, c]}) |
col IN (?, ?, ?) |
where({col => 1..10}) |
col BETWEEN ? AND ? |
where({assoc => $instance}) |
assoc_id = ? (uses $instance.id) |
1 2 3 4 | |
LIKE predicates
LikePredicate builds a LIKE comparison for substring search. The where key is
the column; the predicate carries the pattern.
1 2 3 4 5 6 | |
% and _ in the value are escaped so they match literally; the clause carries
ESCAPE '\', which PostgreSQL, MySQL, and SQLite all accept. It composes with
order, limit, scopes, and count like any other condition.
where.not
where.not(%conditions) adds a negated condition. Nil, ranges, arrays, and
LikePredicate work the same as the positive form.
1 2 3 4 | |
JSON / JSONB predicate operators
For :json / :jsonb columns, pass a
JsonPredicate as the value to query inside the document. Import it with
use ORM::ActiveRecord::Relation::Query::Json;.
1 2 3 4 5 6 7 8 9 10 | |
extract(*@path) walks a nested path and compares the extracted text with
.eq / .ne. All three predicates also work under where.not, which negates
the whole condition. Containment and key-existence need a :jsonb column on
PostgreSQL.
| Predicate | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
extract(path).eq/.ne(v) |
col -> .. ->> .. |
col ->> '$.path' |
col ->> '$.path' |
contains(data) |
col @> ?::jsonb |
JSON_CONTAINS(col, ?) |
— (raises) |
has-key(key) |
jsonb_exists(col, ?) |
JSON_CONTAINS_PATH(col, 'one', ?) |
— (raises) |
where.missing and where.associated
For relations through associations, where.missing(:assoc) finds records
with no associated rows; where.associated(:assoc) finds those that have at
least one. Both work over belongs_to, has_many, and has_many :through.
1 2 3 | |
Model.associated(:assoc) is a class-level shortcut for the common case.
excluding
excluding(*@records-or-ids) removes specific rows from the result set,
mirroring WHERE id NOT IN (...).
1 2 3 | |
It composes:
1 | |
or and and
or(other_relation) and and(other_relation) combine WHERE clauses across
two relations. The result is a single SQL query with the conditions wrapped
in the right boolean structure.
1 2 | |
merge
merge(other_relation) folds another relation's clauses into this one.
Last-wins semantics: other takes precedence for limit, offset,
distinct, and readonly. where, order, joins, and similar additive
clauses are concatenated.
1 2 3 4 5 6 | |
rewhere
rewhere(%conditions) replaces any prior where conditions on the same
columns. Useful when narrowing-then-broadening.
1 2 | |
unscope
unscope(:scope) surgically removes a single relation dimension:
1 2 3 4 | |
You can also drop a single where condition by column:
1 2 3 | |