Cerial
Tuples

Where Filtering

Filtering query results by tuple element values — named and index keys, operators, and array quantifiers.

You can filter query results by the values of individual tuple elements. Conditions use element names (when available) or numeric index keys to target specific positions.

All examples use this schema:

tuple Coordinate {
  lat Float,
  lng Float
}

model User {
  id Record @id
  name String
  location Coordinate
  history Coordinate[]
}

Named Key Filtering

When tuple elements are named, use the element name as the filter key:

const users = await client.db.User.findMany({
  where: { location: { lat: { gt: 40 } } },
});

This returns all users whose location tuple has a lat element greater than 40.

Index Key Filtering

You can also filter using the numeric index (as a string key):

const users = await client.db.User.findMany({
  where: { location: { 0: { gt: 40 } } },
});

This is equivalent to filtering by lat — index 0 refers to the first element. Both named and index keys translate to the same condition.

Comparison Operators on Elements

Every standard filter operator works on tuple elements — comparison, string, existence, and more:

const users = await client.db.User.findMany({
  where: {
    location: {
      lat: { gte: 40, lte: 45 },
      lng: { between: [-80, -70] },
    },
  },
});

For the full list of available operators, see the Filtering section.

Multiple Element Conditions

You can filter on multiple elements at once. All conditions are ANDed together:

const users = await client.db.User.findMany({
  where: {
    location: {
      lat: { gt: 40 },
      lng: { lt: -70 },
    },
  },
});

This returns users whose location has both a latitude greater than 40 and a longitude less than -70.

Logical Operators

Use AND, OR, and NOT to compose more complex conditions:

const users = await client.db.User.findMany({
  where: {
    OR: [
      { location: { lat: { gt: 50 } } },
      { location: { lng: { lt: -100 } } },
    ],
  },
});

You can also combine tuple element filters with top-level field conditions:

const users = await client.db.User.findMany({
  where: {
    name: { startsWith: 'J' },
    location: { lat: { gt: 40 } },
  },
});

Array Tuple Quantifiers

When filtering on array tuple 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: {
    history: { some: { lat: { gt: 40 } } },
  },
});

Returns users where at least one history entry has a latitude greater than 40.

every — All Elements Match

const users = await client.db.User.findMany({
  where: {
    history: { every: { lat: { gte: 0 } } },
  },
});

Returns users where every history entry has a non-negative latitude.

none — No Elements Match

const users = await client.db.User.findMany({
  where: {
    history: { none: { lat: { lt: -90 } } },
  },
});

Returns users where no history entry 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.

Generated Where Type

Cerial generates a TupleNameWhere type for each tuple with both named keys and index keys:

// Generated for Coordinate tuple:
// type CoordinateWhere = {
//   lat?: FloatWhere;   // named key
//   lng?: FloatWhere;   // named key
//   0?: FloatWhere;     // index key
//   1?: FloatWhere;     // index key
// }

Both forms are interchangeable — use whichever is more readable for your use case. Named keys are typically preferred when available.

For the full operator reference, see Filtering.

On this page