Skip to main content

Filtering

The predicate field of a search query selects which records match. This page is the complete reference for predicate syntax: field conditions, comparison and string operators, logical combinators, identity filters, and the exact semantics for types, missing values, nulls, arrays, and datetimes. Filtering by related records is covered separately in Relationships and traversal.

The same predicate syntax is used everywhere a query document appears: listings, aggregations, facets, describe.explain, deleteRecords, the filter of a join side, the selectors of linkRecords, and the predicate of vector and hybrid searches.

Field conditions​

Each key of the predicate object names a property. Several keys are combined with an implicit AND.

{
"labels": ["USER"],
"predicate": {
"status": "active",
"score": { "$gte": 3, "$lte": 5 }
}
}

The value of a key decides how it is read:

Value formMeaningExample
Scalar (string, number, boolean)Equality{ "status": "active" }
nullThe property is present and explicitly null{ "nick": null }
Array of scalarsMembership, same as $in{ "status": ["active", "pending"] }
Object of $ operatorsEvery operator must hold (implicit AND){ "score": { "$gte": 3, "$lte": 5 } }
Any other objectA related-record block keyed by label{ "DEPARTMENT": { "name": "Sales" } } (see Relationships and traversal)

A $-prefixed key that is not an operator from the table below, such as the misspelled { "name": { "$regx": "a" } }, is refused with invalid_request.

Operator reference​

OperatorValueMatches whenMissing property
$eqscalar, null, ISO datetime string, or datetime component objectThe value (or any array element) equals the operand. Strings compare case-sensitively; numbers compare numerically (1 equals 1.0).No match
$neas $eqThe property is present and neither the value nor any array element equals the operand.No match
$gt, $gte, $lt, $ltenumber, ISO datetime string, or datetime component objectThe numeric (or datetime) value, or any numeric array element, satisfies the bound. Strings and booleans never satisfy a range.No match
$inarray of scalarsThe value, or any array element, equals one of the operands.No match
$ninarray of scalarsThe property is present and neither the value nor any array element equals an operand.No match
$containsstringA string value (or string element) contains the operand. Case-insensitive.No match
$startsWithstringA string value (or element) starts with the operand. Case-insensitive.No match
$endsWithstringA string value (or element) ends with the operand. Case-insensitive.No match
$existsbooleantrue: the property is present (even if null). false: it is absent.$exists: false matches
$typetype nameThe property has that type (see Type tests).See Type tests
$year, $month, $day, $hour, $minute, $second, $millisecond, $microsecond, $nanosecondintegerThe datetime value's UTC calendar component equals the operand (see Datetimes).No match
$notoperator objectThe inner operators do not all hold. { "age": { "$not": { "$gte": 4 } } }Matches (the inner condition is false)
$and, $or, $norarray of operator objectsField-scoped logic, see Field-scoped logic.—
$xorarray of exactly twoExactly one of the two holds.—

A predicate on a property that no record has is valid and simply matches nothing.

Logical combinators​

At the top level of predicate (and inside related-record blocks) the combinators take full condition objects:

CombinatorValueMatches when
$andarray of predicatesAll hold.
$orarray of predicatesAt least one holds.
$norarray of predicatesNone holds.
$xorarray of exactly two predicatesExactly one holds. Any other length is invalid_request.
$notone predicate objectThe predicate does not hold.
{
"labels": ["USER"],
"predicate": {
"$or": [
{ "status": "active" },
{ "$and": [{ "status": "pending" }, { "score": { "$gt": 4 } }] }
],
"$not": { "banned": true }
}
}
{ "labels": ["USER"], "predicate": { "$xor": [{ "premium": true }, { "freeAccess": true }] } }

Field-scoped logic​

Inside one field's operator object, $and, $or, $nor and $xor take an array whose elements are operator objects applied to that same field:

{
"labels": ["POST"],
"predicate": {
"created": { "$year": 2011, "$month": 11, "$day": 11 },
"rating": {
"$or": [
{ "$and": [{ "$gt": 4.5 }, { "$lt": 6 }] },
{ "$ne": 3 },
{ "$not": { "$gte": 4 } }
]
}
}
}

An element that names other properties (has non-$ keys) is evaluated as a full predicate instead.

Identity filters​

$id matches the record id. It accepts dashed UUIDs and 32-hex-digit ids, case-insensitively:

{ "predicate": { "$id": "0192f1d2-6c1e-7a40-9d1b-0d6f2c1e4a77" } }
{ "predicate": { "$id": { "$in": ["0192f1d26c1e7a409d1b0d6f2c1e4a77", "0192f1d2-6c1f-7b11-8e2a-5a6b7c8d9e0f"] } } }

$id may also be used inside a related-record block to pin the related record.

Type semantics​

Numbers​

Integers and floating-point numbers form one numeric domain: { "n": 1 } matches a stored 1.0, and range bounds compare across both. Integer range bounds must be exactly representable as a 64-bit float; a bound such as 9007199254740993 is rejected with invalid_request rather than silently rounded.

Strings​

Equality ($eq, $in, $ne, $nin, flat equality) is exact and case-sensitive. $contains, $startsWith and $endsWith lower-case both sides first. Range operators never match strings; to range over text, filter on a datetime or number property instead.

Booleans​

Booleans match only booleans: { "active": true } does not match the string "true" or the number 1.

Missing values and null​

RushDB distinguishes an absent property from one that is present with the value null:

ConditionAbsent propertyPresent, nullPresent, "x"
{ "p": null } or { "p": { "$eq": null } }noyesno
{ "p": { "$exists": true } }noyesyes
{ "p": { "$exists": false } }yesnono
{ "p": { "$ne": "x" } }noyesno
{ "p": { "$nin": ["x"] } }noyesno
{ "$not": { "p": "x" } }yesyesno

$ne and $nin require the property to be present. To include records that lack the property, combine with $exists:

{ "$or": [{ "status": { "$ne": "deleted" } }, { "status": { "$exists": false } }] }

Arrays​

A condition on an array-valued property matches when any element satisfies it. With tags: ["x", "y"]:

ConditionMatches
{ "tags": "x" }yes
{ "tags": ["y", "z"] }yes (any element is in the list)
{ "tags": { "$ne": "x" } }no (an element equals x)
{ "tags": { "$nin": ["z"] } }yes
{ "tags": { "$contains": "X" } }yes (case-insensitive)

Range operators apply to numeric elements the same way.

Type tests​

$type accepts these names (case-insensitive; bool is an alias for boolean):

$type valueMatches
"string", "number", "boolean", "datetime"The property's stored type. A property stored as an array of that type also matches.
"string[]", "number[]", "boolean[]", "datetime[]"An array whose elements have that type.
"array"Any array value.
"object"An object value.
"null"A null value or an absent property.

Note: For the scalar type names, $type consults the type the schema catalog records for the property name, so a value stored as a string in a datetime property matches "datetime". A record that does not carry the property matches only "null".

Datetimes​

RushDB stores datetimes as UTC instants with millisecond precision. When a record is written with default options, string values that parse as one of the following are stored as datetimes (see Properties and types):

  • RFC 3339 timestamps, for example 2023-06-15T12:00:00Z or 2023-06-15T14:00:00+02:00 (a lower-case z is accepted);
  • local timestamps without an offset, 2023-06-15T12:00:00 or 2023-06-15T12:00:00.250, interpreted as UTC;
  • dates, 2023-06-15, interpreted as midnight UTC.

In a predicate you can write a datetime operand three ways:

Operand formExampleWhere accepted
ISO string (any of the formats above)"2023-06-15T00:00:00Z"$eq, $ne, $gt, $gte, $lt, $lte
Component object ($year required; $month, $day default to 1; $hour, $minute, $second, $millisecond default to 0){ "$year": 2024, "$month": 1, "$day": 1 }$eq, $ne, $gt, $gte, $lt, $lte
Epoch milliseconds1686787200000every numeric operator
{ "labels": ["EVENT"], "predicate": { "created": { "$gte": "2023-06-15T00:00:00Z" } } }
{ "labels": ["EVENT"], "predicate": { "created": { "$lt": { "$year": 2024, "$month": 1, "$day": 1 } } } }

Note: Only the explicit operators convert ISO strings. A flat equality such as { "created": "2023-06-15" } compares against the literal string and does not match a datetime property; write { "created": { "$eq": "2023-06-15" } } instead. Values inside $in and $nin are not converted either.

Component operators​

The component operators test one UTC calendar field of a datetime. Several components in one operator object must all match:

{ "labels": ["EVENT"], "predicate": { "created": { "$year": 2023, "$month": 6 } } }
OperatorComponent
$yearCalendar year
$monthMonth, 1–12
$dayDay of month, 1–31
$hourHour, 0–23
$minuteMinute, 0–59
$secondSecond, 0–59
$millisecondSub-second milliseconds, 0–999
$microsecondSub-second microseconds (a multiple of 1,000, since storage is millisecond-precise)
$nanosecondSub-second nanoseconds (a multiple of 1,000,000)

Component values must be integers; anything else is invalid_request.

Errors​

SituationError
Unknown top-level document key (for example where)invalid_request
Operator with the wrong operand type ($in without an array, $exists without a boolean, a non-string $contains)invalid_request
$xor without exactly two operandsinvalid_request
A $ operator used as a top-level key where a property is expected (for example { "$gt": 5 })invalid_request
A filter needs more working memory than the per-query budgetresource_exhausted

Performance notes​

A property filter is answered from a declared ordered index when one exists on that label and property (equality, $in, ranges and $startsWith); otherwise RushDB walks the records of the requested labels that carry the property. Always include labels when you know them. See Indexes and Query planning.

See also​