Where Filtering
Filtering query results by embedded object sub-fields — nested conditions, operators, and array quantifiers.
You can filter query results by the values of nested object fields. Cerial translates these into dot-notation conditions automatically.
All examples use this schema:
object Address {
street String
city String
state String
zipCode String?
}
object GeoPoint {
lat Float
lng Float
label String?
}
model User {
id Record @id
name String
address Address
shipping Address?
locations GeoPoint[]
}Basic Nested Field Filtering
Pass an object with the desired field conditions to filter by nested values:
const users = await client.db.User.findMany({
where: { address: { city: 'NYC' } },
});This returns all users whose address.city equals 'NYC'.
Multiple Nested Conditions
You can specify multiple conditions on the same object. All conditions are ANDed together:
const users = await client.db.User.findMany({
where: {
address: {
state: 'NY',
city: { startsWith: 'New' },
},
},
});You can also filter across different object fields on the same model:
const users = await client.db.User.findMany({
where: {
address: { state: { in: ['NY', 'CA'] } },
shipping: { zipCode: { startsWith: '100' } },
},
});All Operators Work on Nested Fields
Every standard filter operator works on nested object fields — comparison, string, array, existence, and more:
const users = await client.db.User.findMany({
where: {
address: {
city: { contains: 'York' },
state: { neq: 'TX' },
zipCode: { isDefined: true },
},
},
});For the full list of available operators, see the Filtering section — specifically Comparison, String, and Special operators.
Array Object Quantifiers
When filtering on array object fields, use quantifier operators to express how many elements must match: some, every, or none.
some — At Least One Element Matches
const users = await client.db.User.findMany({
where: {
locations: { some: { lat: { gt: 40 } } },
},
});Returns users where at least one location has a latitude greater than 40.
every — All Elements Match
const users = await client.db.User.findMany({
where: {
locations: { every: { lat: { gte: 0 } } },
},
});Returns users where every location has a non-negative latitude.
none — No Elements Match
const users = await client.db.User.findMany({
where: {
locations: { none: { lat: { lt: -90 } } },
},
});Returns users where no location has a latitude less than -90.
The none quantifier is implemented internally as !(arr.any(...)) syntax rather than NOT arr.any(...). This is for SurrealDB 3.x compatibility. The behavior is identical — records where zero elements match the condition.
Combining Object Filters with Other Conditions
Object where conditions combine naturally with top-level field conditions and logical operators:
const users = await client.db.User.findMany({
where: {
name: { startsWith: 'J' },
address: { state: 'NY' },
locations: { some: { lat: { gt: 40 } } },
},
});You can also use AND, OR, and NOT with nested object filters:
const users = await client.db.User.findMany({
where: {
OR: [
{ address: { state: 'NY' } },
{ address: { state: 'CA' } },
],
},
});For the full object filtering reference including deeply nested objects, see Object Filtering.
Cerial supports filtering by embedded object fields. Unlike relations, objects are stored inline within a model record. You can filter on their sub-fields directly and, for array object fields, use quantifier operators to match based on element conditions.
Basic Object Field Filtering
Filter on an embedded object's fields by nesting conditions under the object field name:
// Schema:
// object Address {
// street String
// city String
// state String
// zipCode String?
// }
//
// model User {
// id Record @id
// name String
// address Address
// shipping Address?
// }
// Find users in New York City
const users = await client.db.User.findMany({
where: { address: { city: 'NYC' } },
});Multiple Nested Conditions
You can apply multiple conditions on an embedded object's fields. All conditions within a nested object filter are ANDed together:
const users = await client.db.User.findMany({
where: {
address: {
city: { contains: 'York' },
state: { neq: 'TX' },
},
},
});Filtering Across Multiple Object Fields
You can filter on multiple object fields in the same query:
const users = await client.db.User.findMany({
where: {
address: { state: { in: ['NY', 'CA'] } },
shipping: { zipCode: { startsWith: '100' } },
},
});All Operators Work on Object Fields
Every filter operator available on top-level fields works on nested object fields — comparison, string, array, logical, and special operators:
const users = await client.db.User.findMany({
where: {
address: {
// String operator
city: { contains: 'York' },
// Comparison operator
state: { neq: 'TX' },
// Special operator
zipCode: { isNone: false },
},
},
});// Logical operators inside object filters
const users = await client.db.User.findMany({
where: {
address: {
OR: [{ state: 'NY' }, { state: 'CA' }],
},
},
});Array of Objects — Quantifier Filtering
For array object fields (e.g., locations GeoPoint[]), you use quantifier operators to specify how many elements must match the condition. Three quantifiers are available: some, every, and none.
// Schema:
// object GeoPoint {
// lat Float
// lng Float
// label String?
// }
//
// model User {
// id Record @id
// name String
// locations GeoPoint[]
// }some
Matches records where at least one element in the array matches all specified conditions:
const users = await client.db.User.findMany({
where: {
locations: { some: { lat: { gt: 40 } } },
},
});// At least one location in the northern hemisphere with a label
const users = await client.db.User.findMany({
where: {
locations: {
some: {
lat: { gt: 0 },
label: { isNone: false },
},
},
},
});every
Matches records where all elements in the array match all specified conditions:
const users = await client.db.User.findMany({
where: {
locations: { every: { lat: { gte: 0 } } },
},
});
// All locations must be in the northern hemisphere// All locations must be within a bounding box
const users = await client.db.User.findMany({
where: {
locations: {
every: {
lat: { between: [40, 50] },
lng: { between: [-80, -70] },
},
},
},
});none
Matches records where no elements in the array match the specified conditions:
const users = await client.db.User.findMany({
where: {
locations: { none: { lat: { lt: -90 } } },
},
});
// No locations have an invalid latitude// No locations are in the southern hemisphere
const users = await client.db.User.findMany({
where: {
locations: { none: { lat: { lt: 0 } } },
},
});The none quantifier uses !(arr.any(...)) syntax internally for SurrealDB 3.x compatibility. This is handled automatically — you just use none in your filter object.
Complex Quantifier Conditions
Quantifiers can use any combination of filter operators on the object's fields:
const users = await client.db.User.findMany({
where: {
locations: {
some: {
lat: { between: [40, 50] },
lng: { lt: -70 },
label: { contains: 'office' },
},
},
},
});Combining Object Filters with Other Filters
Object filters combine seamlessly with top-level field filters, relation filters, and logical operators:
const users = await client.db.User.findMany({
where: {
// Direct field filter
isActive: true,
// Object field filter
address: { state: 'NY' },
// Array object quantifier
locations: { some: { lat: { gt: 40 } } },
// Logical operator
OR: [
{ name: { startsWith: 'A' } },
{ name: { startsWith: 'B' } },
],
},
});// Combine object filtering with nested relation filtering
const users = await client.db.User.findMany({
where: {
address: { city: 'NYC' },
posts: { status: 'published' },
},
});Optional Object Fields
Optional embedded objects (Address?) can be filtered the same way. If the object field is absent (NONE) on a record, it will not match any sub-field conditions:
// Only matches users who have a shipping address with state 'CA'
// Users without a shipping address are excluded
const users = await client.db.User.findMany({
where: {
shipping: { state: 'CA' },
},
});Flexible Objects
Objects decorated with @flexible accept arbitrary additional fields beyond those defined in the schema. The Where type for flexible object fields includes & { [key: string]: any }, allowing you to filter on extra keys:
// Schema:
// model Config {
// id Record @id
// metadata Metadata @flexible
// }
// Filter on a known field
const configs = await client.db.Config.findMany({
where: {
metadata: { version: '2.0' },
},
});
// Filter on an extra field not defined in the schema
const configs = await client.db.Config.findMany({
where: {
metadata: { customFlag: true },
},
});