Data Access

Filtering

Filter items by conditions using comparison, string, logical, and relational operators.

Filter by Exact Value

Use _eq to match items where a field equals a specific value.

Return all published articles:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: { status: { _eq: 'published' } },
});
Shorthand equality is supported — pass a value directly instead of { _eq: value }. This works in both REST (filter[status]=published) and the SDK (filter: { status: 'published' }). See Type System for typed shorthand.

Compare with Greater Than / Less Than

Use _gt, _gte, _lt, and _lte to compare numeric, date, or string values.

Return articles with more than 1000 words:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'word_count'],
  filter: { word_count: { _gt: 1000 } },
});

These operators also work with dates (passed as ISO 8601 strings through string filters). Return articles published after January 1, 2026:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'published_at'],
  filter: { published_at: { _gte: '2026-01-01' } },
});

Check if a Value is Between Two Bounds

Use _between to match values within an inclusive range. Pass two values as the lower and upper bound. Use _nbetween to match values outside the range.

Return articles with a word count between 500 and 2000:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'word_count'],
  filter: { word_count: { _between: [500, 2000] } },
});

Exclude articles in that range with _nbetween:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'word_count'],
  filter: { word_count: { _nbetween: [500, 2000] } },
});

Check if a Value is in a List

Use _in to match any value in a set. Use _nin to exclude values in a set.

Return articles that are either published or featured:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: { status: { _in: ['published', 'featured'] } },
});

Exclude draft and archived articles:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: { status: { _nin: ['draft', 'archived'] } },
});

Search Text with Contains

Use _contains for case-sensitive substring matching and _icontains for case-insensitive. Use _ncontains and _nicontains to negate.

Return articles with "TypeScript" in the title:

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { title: { _contains: 'TypeScript' } },
});

Case-insensitive search for "graphql" in any casing:

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { title: { _icontains: 'graphql' } },
});

Exclude articles containing "Draft":

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { title: { _ncontains: 'Draft' } },
});

Search Text with Starts With / Ends With

Use _starts_with and _ends_with to match the beginning or end of a string. Use _nstarts_with and _nends_with to negate.

Return articles with a slug starting with "2026-":

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'slug'],
  filter: { slug: { _starts_with: '2026-' } },
});

Exclude authors with a test email domain:

const authors = await client.Authors.readMany({
  fields: ['id', 'name', 'email'],
  filter: { email: { _nends_with: '@test.com' } },
});

Negate a Filter

Use _not to negate a filter condition. _not accepts a single filter object (not an array).

Return articles that are not in draft status:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: {
    _not: { status: { _eq: 'draft' } },
  },
});

Combine Conditions with AND (Implicit)

Place multiple conditions at the top level of the filter object. All conditions must be true for an item to match — multiple keys at the same level are automatically combined with AND.

Return published articles by a specific author:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: { status: 'published', author_id: 5 },
});

This implicit AND is convenient for simple cases where you filter on different fields. For more complex boolean logic — such as multiple conditions on the same field, or combining AND with OR — use explicit _and.


Combine Conditions with AND (Explicit)

Use _and when you need to express complex boolean logic that implicit AND cannot cover. _and takes an array of filter objects, all of which must match.

Return articles that are both published and have more than 1000 words:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status', 'word_count'],
  filter: {
    _and: [
      { status: 'published' },
      { word_count: { _gt: 1000 } },
    ],
  },
});

Explicit _and is especially useful when nesting inside an _or to build compound conditions (see Nest AND and OR Conditions).


Combine Conditions with OR

Use _or to match items that satisfy at least one condition.

Return articles that are published or featured:

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status'],
  filter: {
    _or: [
      { status: 'published' },
      { status: 'featured' },
    ],
  },
});

Nest AND and OR Conditions

Combine _and and _or for complex logic. Each can contain the other.

Return articles that are either (published by author 5) or (featured with more than 2000 words):

const articles = await client.Articles.readMany({
  fields: ['id', 'title', 'status', 'word_count'],
  filter: {
    _or: [
      {
        _and: [
          { status: 'published' },
          { author_id: 5 },
        ],
      },
      {
        _and: [
          { status: 'featured' },
          { word_count: { _gt: 2000 } },
        ],
      },
    ],
  },
});

Filter items based on a to-one related item's fields. Nest the related collection's field conditions inside the relation field name.

Filtering on a to-one relation is only supported for nullable relations. This honors the output contract — a non-nullable relation field guarantees a value is always present, so excluding items based on a filter on that relation would violate that contract by potentially returning null where the type says it cannot.

Return articles written by an author named "Jane":

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { author: { name: { _eq: 'Jane' } } },
});

You can chain multiple levels deep:

const comments = await client.Comments.readMany({
  fields: ['id', 'body'],
  filter: { article: { author: { name: { _eq: 'Jane' } } } },
});

Filter To-Many Relations with Quantifiers

Use _some, _none, and _every to control how a to-many relation is evaluated.

  • _some — at least one related item matches
  • _none — no related items match
  • _every — all related items match

Return articles that have at least one tag named "TypeScript":

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { tags: { _some: { name: { _eq: 'TypeScript' } } } },
});

Return articles with no flagged comments:

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { comments: { _none: { flagged: { _eq: true } } } },
});

Return articles where every tag is approved:

const articles = await client.Articles.readMany({
  fields: ['id', 'title'],
  filter: { tags: { _every: { approved: { _eq: true } } } },
});
Without a quantifier, filtering on a to-many relation defaults to _some.

Operator Reference

Comparison Operators

OperatorDescriptionApplies ToExample Value
_eqEqual toAll types'published'
_neqNot equal toAll types'draft'
_gtGreater thanString, Number1000
_gteGreater than or equal toString, Number500
_ltLess thanString, Number2000
_lteLess than or equal toString, Number1500
_inIn a set of valuesString, Number, UUID['published', 'featured']
_ninNot in a set of valuesString, Number, UUID['draft', 'archived']
_betweenBetween two values (inclusive)Number[500, 2000]
_nbetweenNot between two valuesNumber[500, 2000]

String Operators

OperatorDescriptionExample Value
_containsContains substring (case-sensitive)'TypeScript'
_ncontainsDoes not contain substring'Draft'
_icontainsContains substring (case-insensitive)'graphql'
_nicontainsDoes not contain substring (case-insensitive)'test'
_starts_withStarts with'2026-'
_nstarts_withDoes not start with'test-'
_ends_withEnds with'@example.com'
_nends_withDoes not end with'@test.com'

Logical Operators

OperatorDescriptionValue Type
_andAll conditions must matchArray of filter objects
_orAt least one condition must matchArray of filter objects
_notNegate the conditionSingle filter object

Relational Quantifiers (To-Many Only)

OperatorDescriptionValue Type
_someAt least one related item matchesFilter object
_noneNo related items matchFilter object
_everyAll related items matchFilter object

Related pages:

  • Reading Data — fetch items with sorting, pagination, and field selection
  • Writing Data — use filters in updateMany and deleteMany operations
  • Field Selection — control which fields are returned
Copyright © 2026