Cerial
Filtering

Object Filtering

Filter on embedded object sub-fields and use quantifier operators (some, every, none) for object array 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 },
  },
});

On this page