Фильтрация и сортировка

На странице GraphQL API — краткая сводка операторов. Здесь — полный справочник: все операторы по типам полей, комбинаторы, сортировка, системные колонки и наследованные поля.

Фильтр Where

Структурированный фильтр передаётся в аргументе where:

query {
  blogPosts(where: { status: { eq: "published" } }) {
    id title
  }
}

Каждое поле в where — это объект с оператором. Тип оператора зависит от типа поля.

Операторы по типам полей

Тип поля Операторы
Строка, Текст, Список eq, neq, in, notIn, contains, startsWith, endsWith
Число eq, neq, gt, gte, lt, lte, in
Логический eq
Дата, Дата и время eq, neq, gt, gte, lt, lte
Тип контента (ссылка) eq, in
Массив (значений) contains, eq, in, notIn

Примеры:

# Строка: подстрока (без учёта регистра)
where: { title: { contains: "vue" } }

# Число: больше или равно
where: { view_count: { gte: 100 } }

# Логический: равно
where: { featured: { eq: true } }

# Дата: больше (ISO 8601)
where: { published_at: { gt: "2026-01-01T00:00:00Z" } }

# Ссылка: равно (по ID)
where: { author: { eq: "550e8400-e29b-41d4-a716-446655440000" } }

# Массив: содержит (проверка вхождения элемента)
where: { tags: { contains: "vue" } }

# Множественный выбор
where: { status: { in: ["draft", "review"] } }

Регистр

contains, startsWith, endsWithбез учёта регистра (ILIKE). eq и neq на строках — с учётом регистра. { title: { eq: "Vue" } } не найдёт "vue", но { title: { contains: "vue" } } найдёт.

Пустые списки

{ slug: { in: [] } } возвращает 0 записей. { slug: { notIn: [] } } возвращает все записи.

Комбинаторы AND / OR / NOT

Поля на одном уровне объединяются через AND (неявно):

where: {
  status: { eq: "published" }     # AND
  view_count: { gte: 100 }        # AND
}

OR — список фильтров (выполняется хотя бы один):

where: {
  title: { contains: "Vue" }
  OR: [
    { status: { eq: "draft" } }
    { view_count: { gte: 75 } }
  ]
}
# означает: title contains "Vue" AND (status = draft OR view_count >= 75)

AND — список (явное AND внутри группы):

where: {
  AND: [
    { status: { eq: "published" } }
    { author: { eq: "abc-123" } }
  ]
}

NOT — один объект (не список):

where: {
  NOT: { status: { eq: "draft" } }
}
# означает: status ≠ draft

Комбинаторы вкладываются друг в друга без ограничений.

Сортировка (orderBy)

Список полей и направлений:

query {
  blogPosts(orderBy: [{ field: PUBLISHED_AT, direction: DESC }]) {
    title published_at
  }
}

Множественная сортировка — по первому ключу, потом по второму:

orderBy: [{ field: STATUS, direction: DESC }, { field: CREATED_AT, direction: ASC }]

Правила:

  • Имена полей — в верхнем регистре (PUBLISHED_AT, TITLE, CREATED_AT).
  • Направление: ASC (по умолчанию) или DESC.
  • Массивы сортировать нельзя.

Системные поля

Эти поля есть у каждого типа, независимо от схемы:

Поле Фильтр Сортировка
id eq, in да
created_at дата да
updated_at дата да
where: { created_at: { gt: "2026-01-01T00:00:00Z" } }
orderBy: [{ field: CREATED_AT, direction: DESC }]

Наследованные поля

Если тип наследует поля через Extends, эти поля тоже доступны для фильтрации и сортировки. Например, blog-post наследует status от page — фильтр where: { status: { eq: "published" } } работает.

Какие поля НЕ фильтруются

  • JSON — произвольный JSON нельзя сравнить.
  • Полиморфные блоки (blocks у Page — Тип контента + массив без указания типа) — нельзя фильтровать и сортировать.
  • Неизвестное поле в where вызывает ошибку.

Search vs Where

Аргумент search — поиск подстроки по всем значениям записи и по её ID (ILIKE по JSONB и колонке id). Комбинируется с where через AND:

blogPosts(search: "vue", where: { status: { eq: "published" } })

search ищет везде, where фильтрует по конкретным полям.

Count с фильтром

blogPostsCount(where: { status: { eq: "published" } })

Возвращает количество записей под фильтром — для пагинации. Игнорирует limit и offset.

Что дальше