Skip to main content

GraphQL API

GraphQL API 允许通过 Strapi 的 GraphQL 插件内容类型 执行查询和变更。结果可以被 过滤排序分页

🌐 The GraphQL API allows performing queries and mutations to interact with the content-types through Strapi's GraphQL plugin. Results can be filtered, sorted and paginated.

Prerequisites

要使用 GraphQL API,请安装 GraphQL 插件:

🌐 To use the GraphQL API, install the GraphQL plugin:

yarn add @strapi/plugin-graphql

安装完成后,GraphQL playground 可通过 /graphql URL 访问,并可用于交互式构建查询和变更操作,以及阅读针对你的内容类型定制的文档:

🌐 Once installed, the GraphQL playground is accessible at the /graphql URL and can be used to interactively build your queries and mutations and read documentation tailored to your content-types:

GraphQL playground use exampleGraphQL playground use example

GraphQL 插件只公开一个处理所有查询和变更的端点。默认端点是 /graphql,并在 插件配置文件 中定义:

🌐 The GraphQL plugin exposes only one endpoint that handles all queries and mutations. The default endpoint is /graphql and is defined in the plugins configuration file:

/config/plugins.js|ts
  export default {
shadowCRUD: true,
endpoint: '/graphql', // <— single GraphQL endpoint
subscriptions: false,
maxLimit: -1,
apolloServer: {},
v4CompatibilityMode: process.env.STRAPI_GRAPHQL_V4_COMPATIBILITY_MODE ?? false,
};
No GraphQL API to upload media files

GraphQL API 不支持媒体上传。请使用 REST API POST /upload 端点 进行所有文件上传,并使用返回的信息在内容类型中链接它。你仍然可以使用 updateUploadFiledeleteUploadFile 变更通过媒体文件 id 更新或删除已上传的文件(参见 媒体文件的变更)。

🌐 The GraphQL API does not support media upload. Use the REST API POST /upload endpoint for all file uploads and use the returned info to link to it in content types. You can still update or delete uploaded files with the updateUploadFile and deleteUploadFile mutations using media files id (see mutations on media files).

Caution
documentId only

GraphQL API 仅使用 documentId 字段公开文档。之前的数字 id 在这里不再可用,尽管它仍然通过 REST API 返回以保持向后兼容性(详见 breaking change)。

🌐 The GraphQL API exposes documents using only the documentId field. The previous numeric id is no longer available here, although it is still returned by the REST API for backward compatibility (see breaking change for details).

查询

🌐 Queries

GraphQL 中的查询用于获取数据而不修改数据。

🌐 Queries in GraphQL are used to fetch data without modifying it.

当将内容类型添加到你的项目时,2 个自动生成的 GraphQL 查询将添加到你的架构中,以内容类型的单数和复数 API ID 命名,如下例所示:

🌐 When a content-type is added to your project, 2 automatically generated GraphQL queries are added to your schema, named after the content-type's singular and plural API IDs, as in the following example: | 内容类型显示名称 | 单数 API ID | 复数 API ID ||----------------|-----------------|---------------|| 餐厅 | restaurant | restaurants |

单数 API ID 与复数 API ID:

在内容类型生成器中创建内容类型时,会定义单数 API ID 和复数 API ID 值,并且可以在管理面板中编辑内容类型时找到(参见 用户指南)。你可以在创建内容类型时定义自定义 API ID,但之后无法修改这些 ID。

🌐 Singular API ID and Plural API ID values are defined when creating a content-type in the Content-Type Builder, and can be found while editing a content-type in the admin panel (see User Guide). You can define custom API IDs while creating the content-type, but these can not modified afterwards.

Screenshot of the Content-Type Builder to retrieve singular and plural API IDsScreenshot of the Content-Type Builder to retrieve singular and plural API IDs

获取单个文档

🌐 Fetch a single document

可以通过它们的 documentId 获取文档

Example query: Find a restaurant with its documentId
{
restaurant(documentId: "a1b2c3d4e5d6f7g8h9i0jkl") {
name
description
}
}

获取多个文档

🌐 Fetch multiple documents

要获取多个文档 你可以使用简单的、扁平的查询或 Relay-style 查询:

扁平查询只返回每个文档中请求的字段。Relay 风格查询以 _connection 结尾,并返回一个 nodes 数组以及一个 pageInfo 对象。当你需要分页元数据时,请使用 Relay 风格查询。

🌐 Flat queries return only the requested fields for each document. Relay-style queries end with _connection and return a nodes array together with a pageInfo object. Use Relay-style queries when you need pagination metadata.

要获取多个文档,你可以使用如下所示的扁平查询:

🌐 To fetch multiple documents you can use flat queries like the following:

Example query: Find all restaurants
restaurants {
documentId
title
}

获取关系

🌐 Fetch relations

你可以在你的扁平查询或你的 Relay-style 查询中请求包含关联数据:

以下示例获取所有“Restaurant”内容类型的文档,并且对于每个文档,还返回与“Category”内容类型的多对多关系的一些字段:

🌐 The following example fetches all documents from the "Restaurant" content-type, and for each of them, also returns some fields for the many-to-many relation with the "Category" content-type:

Example query: Find all restaurants and their associated categories
{
restaurants {
documentId
name
description
# categories is a many-to-many relation
categories {
documentId
name
}
}
}

获取媒体字段

🌐 Fetch media fields

媒体字段内容的获取方式与其他属性一样。

🌐 Media fields content is fetched just like other attributes.

以下示例获取“Restaurants”内容类型中附加到每个文档的每个 cover 媒体字段的 url 属性值:

🌐 The following example fetches the url attribute value for each cover media field attached to each document from the "Restaurants" content-type:

{
restaurants {
images {
documentId
url
}
}
}

对于多个媒体字段,你可以使用扁平查询或 Relay-style 查询:

以下示例从“餐厅”内容类型中找到的 images 多媒体字段获取一些属性:

🌐 The following example fetches some attributes from the images multiple media field found in the "Restaurant" content-type:

{
restaurants {
images_connection {
nodes {
documentId
url
}
}
}
}

获取组件

🌐 Fetch components

组件内容的获取方式与其他属性一样。

🌐 Components content is fetched just like other attributes.

以下示例获取每个文档中添加的每个 closingPeriod 组件的 labelstart_dateend_date 属性值,这些文档来自“餐馆”内容类型:

🌐 The following example fetches the label, start_date, and end_date attributes values for each closingPeriod component added to each document from the "Restaurants" content-type:

{
restaurants {
closingPeriod {
label
start_date
end_date
}
}
}

获取动态区域数据

🌐 Fetch dynamic zone data

动态区域是在 GraphQL 中的联合类型,因此你需要使用 fragments (即使用 ...on)来查询字段,并将组件名称(使用 ComponentCategoryComponentname 语法)传递给 `__typename`

以下示例获取可以添加到“dz”动态区域的“Default”组件类别中“Closingperiod”组件的 label 属性的数据:

🌐 The following example fetches data for the label attribute of a "Closingperiod" component from the "Default" components category that can be added to the "dz" dynamic zone:

{
restaurants {
dz {
__typename
...on ComponentDefaultClosingperiod {
# define which attributes to return for the component
label
}
}
}
}

获取草稿或已发布的版本

🌐 Fetch draft or published versions

如果内容类型启用了 Draft & Publish 功能,你可以在查询中添加 status 参数以获取文档的草稿或已发布版本

Example: Fetch draft versions of documents
query Query($status: PublicationStatus) {
restaurants(status: DRAFT) {
documentId
name
publishedAt # should return null
}
}
Example: Fetch published versions of documents
query Query($status: PublicationStatus) {
restaurants(status: PUBLISHED) {
documentId
name
publishedAt
}
}

聚合

🌐 Aggregations

聚合可以用于计算统计量,例如计数、总和或分组总计,而无需单独获取每个文档。聚合通过 Relay-style 连接查询公开:每种集合类型在其<plural>_connection查询下都包含一个aggregate字段。

Example: Total restaurants matching a filter
{
restaurants_connection(filters: { categories: { documentId: { eq: "food-trucks" } } }) {
aggregate {
count
}
}
}

聚合遵循与父查询相同的筛选条件、语言环境、发布状态和权限。例如,在连接上设置 locale: "fr"status: DRAFT 会将聚合限制为那些文档,并且用户只能聚合他们被允许阅读的内容。

🌐 Aggregations follow the same filters, locale, publication status, and permissions as the parent query. For example, setting locale: "fr" or status: DRAFT on the connection limits the aggregation to those documents, and users can only aggregate content they are allowed to read.

下表列出了所有受支持的聚合运算符:

🌐 The table below lists all supported aggregation operators: | 操作符 | 描述 | 支持的字段类型 || --- | --- | --- || count | 返回匹配查询的文档数量。 | 所有内容类型 || avg | 计算每个数值字段的算术平均值。 | 数字、整数、小数 || sum | 计算每个数值字段的总和。 | 数字、整数、小数 || min | 返回每个字段的最小值。 | 数字、整数、小数、日期、日期时间 || max | 返回每个字段的最大值。 | 数字、整数、小数、日期、日期时间 || groupBy | 按唯一值对结果进行分组,并为每个分组提供嵌套聚合。 | 标量字段(字符串、数字、布尔值、日期、日期时间)、关联字段 |

Note

Strapi 会忽略 avgsumminmaxnull 值。在聚合关系时,操作符会在目标文档上运行,并且仍然遵守其语言环境和权限。

🌐 Strapi ignores null values for avg, sum, min, and max. When aggregating relations, the operators run on the target documents and still respect their locales and permissions.

Performance & limits

聚合在服务器端运行,因此通常比在客户端下载和处理大量结果集更快。然而,复杂的 groupBy 树和宽投影仍可能开销较大。请使用过滤器来限制数据集,并考虑相应设置 depthLimitamountLimit 值(参见 可用选项)以保护你的 API。诸如 You are not allowed to perform this action 的错误通常意味着请求者在目标集合上缺少 Read 权限。

🌐 Aggregations operate server-side, so they are generally faster than downloading and processing large result sets on the client. However, complex groupBy trees and wide projections can still be expensive. Use filters to restrict the data set and consider setting up depthLimit and amountLimit values accordingly (see available options) to protect your API. Errors such as You are not allowed to perform this action usually mean the requester lacks the Read permission on the target collection.

在一个请求中汇总多个指标

🌐 Aggregate multiple metrics in one request

可以组合聚合,以便一次网络往返返回多个指标:

🌐 Aggregations can be combined so that one network round trip returns several metrics:

Example: Average delivery time and minimum price
{
restaurants_connection(filters: { takeAway: { eq: true } }) {
aggregate {
avg {
delivery_time
}
min {
price_range
}
max {
price_range
}
}
}
}

分组结果

🌐 Group results

使用 groupBy 来推导分组指标,同时可以选择在每个组内进一步链式聚合。每个组都会展示唯一的 key 以及一个嵌套的连接,可用于下钻或统计分组项:

🌐 Use groupBy to derive grouped metrics while optionally chaining further aggregations inside each group. Each group exposes the unique key and a nested connection that can be used for drilling down or counting the grouped items:

Example: Count restaurants per category
{
restaurants_connection {
aggregate {
groupBy {
categories {
key
connection {
aggregate {
count
}
}
}
}
}
}
}

组继承顶层过滤器。要进一步细化特定组,请在嵌套的 connection 上应用过滤器。

🌐 Groups inherit the top-level filters. To further refine a specific group, apply filters on the nested connection.

与分页和排序结合

🌐 Combine with pagination and sorting

聚合运行在匹配查询过滤条件的整个结果集上,而不仅仅是当前页面。当请求包含分页参数和聚合时,nodes 中的文档遵循分页限制,但 aggregate 内的值会忽略 pageSizelimit,因此它们描述的是整个集合。你仍然可以添加排序以对返回的带聚合结果的文档进行排序。

🌐 Aggregations run on the entire result set that matches the query filters, not only on the current page. When a request includes pagination arguments and aggregations, the documents in nodes follow the pagination limits, but the values inside aggregate ignore pageSize or limit so they describe the whole set. You can still add sorting to order the documents returned with the aggregation results.

Example: Paginate takeaway restaurants and count all matches
{
restaurants_connection(
filters: { takeAway: { eq: true } }
pagination: { page: 2, pageSize: 5 }
sort: "name:asc"
) {
nodes {
documentId
name
rating
}
pageInfo {
page
pageSize
total
}
aggregate {
count
avg {
rating
}
}
}
}

突变

🌐 Mutations

GraphQL 中的突变用于修改数据(例如创建、更新和删除数据)。

🌐 Mutations in GraphQL are used to modify data (e.g. create, update, and delete data).

当将内容类型添加到你的项目时,将向你的架构添加 3 个自动生成的 GraphQL 修改,用于创建、更新和删除文档

例如,对于“餐厅”内容类型,会生成以下变更:

🌐 For instance, for a "Restaurant" content-type, the following mutations are generated: | 用例 | 单一 API ID ||---------------------------------------------|---------------------|| 创建一个新的“餐厅”文档 | createRestaurant || 更新一个现有的“餐厅”餐厅 | updateRestaurant || 删除一个现有的“餐厅”餐厅 | deleteRestaurant |

创建新文档

🌐 Create a new document

在创建新文档时,data 参数将具有与你的内容类型特定相关的输入类型。

🌐 When creating new documents, the data argument will have an associated input type that is specific to your content-type.

例如,如果你的 Strapi 项目包含“餐厅”内容类型,你将拥有以下内容:

🌐 For instance, if your Strapi project contains the "Restaurant" content-type, you will have the following: | 突变 | 参数 | 输入类型 ||--------------------|------------------|--------------------|| createRestaurant | data | RestaurantInput! |

以下示例为“餐厅”内容类型创建一个新文档,并返回其 namedocumentId

🌐 The following example creates a new document for the "Restaurant" content-type and returns its name and documentId:

mutation CreateRestaurant($data: RestaurantInput!) {
createRestaurant(data: {
name: "Pizzeria Arrivederci"
}) {
name
documentId
}
}

创建新文档时,会自动生成一个 documentId

🌐 When creating a new document, a documentId is automatically generated.

突变的实现也支持关系属性。例如,你可以创建一个新的“类别”,并通过编写如下查询,将许多“餐馆”(使用它们的 documentId)附加到它上面:

🌐 The implementation of the mutations also supports relational attributes. For example, you can create a new "Category" and attach many "Restaurants" (using their documentId) to it by writing your query like follows:

mutation CreateCategory {
createCategory(data: {
Name: "Italian Food"
restaurants: ["a1b2c3d4e5d6f7g8h9i0jkl", "bf97tfdumkcc8ptahkng4puo"]
}) {
documentId
Name
restaurants {
documentId
name
}
}
}
Tip

如果你的内容类型启用了国际化 (i18n) 功能,你可以为特定的区域创建文档(参见 创建新的本地化文档)。

🌐 If the Internationalization (i18n) feature is enabled for your content-type, you can create a document for a specific locale (see create a new localized document).

更新现有文档

🌐 Update an existing document

在更新现有文档 时,传递包含新内容的 documentIddata 对象。data 参数将具有与你的内容类型特定的关联输入类型。

例如,如果你的 Strapi 项目包含“餐厅”内容类型,你将拥有以下内容:

🌐 For instance, if your Strapi project contains the "Restaurant" content-type, you will have the following: | 突变 | 参数 | 输入类型 ||--------------------|------------------|--------------------|| updateRestaurant | data | RestaurantInput! |

例如,以下示例会更新一个现有的“餐厅”内容类型的文档,并给它一个新名称:

🌐 For instance, the following example updates an existing document from the "Restaurants" content-type and give it a new name:

mutation UpdateRestaurant($documentId: ID!, $data: RestaurantInput!) {
updateRestaurant(
documentId: "bf97tfdumkcc8ptahkng4puo",
data: { name: "Pizzeria Amore" }
) {
documentId
name
}
}
Tip

如果为你的内容类型启用了国际化 (i18n) 功能,你可以为特定的区域创建文档(参见 i18n 文档)。

🌐 If the Internationalization (i18n) feature is enabled for your content-type, you can create a document for a specific locale (see i18n documentation).

更新关系

🌐 Update relations

你可以通过传递一个 documentId 或一个 documentId 数组(取决于关系类型)来更新关系属性。

🌐 You can update relational attributes by passing a documentId or an array of documentId (depending on the relation type).

例如,以下示例会更新“Restaurant”内容类型的文档,并通过 categories 关联字段向“Category”内容类型的文档添加关联:

🌐 For instance, the following example updates a document from the "Restaurant" content-type and adds a relation to a document from the "Category" content-type through the categories relation field:

mutation UpdateRestaurant($documentId: ID!, $data: RestaurantInput!) {
updateRestaurant(
documentId: "slwsiopkelrpxpvpc27953je",
data: { categories: ["kbbvj00fjiqoaj85vmylwi17"] }
) {
documentId
name
categories {
documentId
Name
}
}
}

删除文档

🌐 Delete a document

要删除文档 ,传入其 documentId

mutation DeleteRestaurant {
deleteRestaurant(documentId: "a1b2c3d4e5d6f7g8h9i0jkl") {
documentId
}
}
Tip

如果你的内容类型启用了国际化 (i18n) 功能,你可以删除文档的特定本地化版本(参见 i18n 文档)。

🌐 If the Internationalization (i18n) feature is enabled for your content-type, you can delete a specific localized version of a document (see i18n documentation).

媒体文件的修改

🌐 Mutations on media files

Caution

目前,媒体字段上的变更使用 Strapi v4 id,而不是 Strapi 5 documentId,作为媒体文件的唯一标识符。

🌐 Currently, mutations on media fields use Strapi v4 id, not Strapi 5 documentId, as unique identifiers for media files.

媒体字段的变更使用文件 id。然而,Strapi 5 中的 GraphQL API 查询不再返回 id。可以找到媒体文件 id

🌐 Media fields mutations use files id. However, GraphQL API queries in Strapi 5 do not return id anymore. Media files id can be found:

  • 也可以在管理员面板的媒体库中,

    Media Library screenshot highlighting how to find a media file idMedia Library screenshot highlighting how to find a media file id
  • 或者通过发送 REST API GET 请求来填充媒体文件,因为 REST API 请求目前会返回媒体文件的 iddocumentId

更新已上传的媒体文件

🌐 Update an uploaded media file

在更新已上传的媒体文件时,传入媒体的 id(而不是它的 documentId)以及包含新内容的 info 对象。info 参数将具有与媒体文件特定相关的输入类型。

🌐 When updating an uploaded media file, pass the media's id (not its documentId) and the info object containing new content. The info argument will has an associated input type that is specific to media files.

例如,如果你的 Strapi 项目包含“餐厅”内容类型,你将拥有以下内容:

🌐 For instance, if your Strapi project contains the "Restaurant" content-type, you will have the following: | 突变 | 参数 | 输入类型 ||--------------------|------------------|--------------------|| updateUploadFile | info | FileInfoInput! |

例如,下面的示例更新了 id 为 3 的媒体文件的 alternativeText 属性:

🌐 For instance, the following example updates the alternativeText attribute for a media file whose id is 3:

mutation Mutation($updateUploadFileId: ID!, $info: FileInfoInput) {
updateUploadFile(
id: 3,
info: {
alternativeText: "New alt text"
}
) {
documentId
url
alternativeText
}
}
Tip

如果上传变更返回禁止访问错误,请确保为上传插件设置了适当的权限(参见用户指南)。

🌐 If upload mutations return a forbidden access error, ensure proper permissions are set for the Upload plugin (see User Guide).

删除已上传的媒体文件

🌐 Delete an uploaded media file

在删除已上传的媒体文件时,传递媒体的 id(而不是它的 documentId)。

🌐 When deleting an uploaded media file, pass the media's id (not its documentId).

Example: Delete the media file with id 4
mutation DeleteUploadFile($deleteUploadFileId: ID!) {
deleteUploadFile(id: 4) {
documentId # return its documentId
}
}
Tip

如果上传变更返回禁止访问错误,请确保为上传插件设置了适当的权限(参见用户指南)。

🌐 If upload mutations return a forbidden access error, ensure proper permissions are set for the Upload plugin (see User Guide).

过滤器

🌐 Filters

查询可以接受带有以下语法的 filters 参数:

🌐 Queries can accept a filters parameter with the following syntax:

filters: { field: { operator: value } }

多个筛选器可以组合在一起,逻辑运算符(andornot)也可以使用,并且接受对象数组。当多个字段条件被组合时,它们会默认使用 and 连接。

🌐 Multiple filters can be combined together, and logical operators (and, or, not) can also be used and accept arrays of objects. When multiple field conditions are combined, they are implicitly joined with and.

Tip

andornot 运算符可以互相嵌套。

可以使用以下运算符:

🌐 The following operators are available: | 操作符 | 描述 || --- | --- || eq | 等于 || eqi | 等于,忽略大小写 || ne | 不等于 || nei | 不等于,忽略大小写 || lt | 小于 || lte | 小于或等于 || gt | 大于 || gte | 大于或等于 || in | 包含于数组中 || notIn | 不包含于数组中 || contains | 包含,区分大小写 || notContains | 不包含,区分大小写 || containsi | 包含,忽略大小写 || notContainsi | 不包含,忽略大小写 || null | 为空 || notNull | 不为空 || between | 介于之间 || startsWith | 以...开头 || endsWith | 以...结尾 || and | 逻辑 and || or | 逻辑 or || not | 逻辑 not |

Simple examples for comparison operators (eq, ne, lt, lte, gt, gte, between)
# eq - returns restaurants with the exact name "Biscotte"
{
restaurants(filters: { name: { eq: "Biscotte" } }) {
name
}
}

# eqi - returns restaurants whose name equals "Biscotte",
# comparison is case-insensitive
{
restaurants(filters: { name: { eqi: "Biscotte" } }) {
name
}
}

# ne - returns restaurants whose name is not "Biscotte"
{
restaurants(filters: { name: { ne: "Biscotte" } }) {
name
}
}

# nei - returns restaurants whose name is not "Biscotte",
# comparison is case-insensitive
{
restaurants(filters: { name: { nei: "Biscotte" } }) {
name
}
}

# lt - returns restaurants with averagePrice less than 20
{
restaurants(filters: { averagePrice: { lt: 20 } }) {
name
}
}

# lte - returns restaurants with averagePrice less than or equal to 20
{
restaurants(filters: { averagePrice: { lte: 20 } }) {
name
}
}

# gt - returns restaurants with averagePrice greater than 20
{
restaurants(filters: { averagePrice: { gt: 20 } }) {
name
}
}

# gte - returns restaurants with averagePrice greater than or equal to 20
{
restaurants(filters: { averagePrice: { gte: 20 } }) {
name
}
}

# between - returns restaurants with averagePrice between 10 and 30
{
restaurants(filters: { averagePrice: { between: [10, 30] } }) {
name
}
}
Simple examples for membership operators (in, notIn)
# in - returns restaurants with category either "pizza" or "burger"
{
restaurants(filters: { category: { in: ["pizza", "burger"] } }) {
name
}
}

# notIn - returns restaurants whose category is neither "pizza" nor "burger"
{
restaurants(filters: { category: { notIn: ["pizza", "burger"] } }) {
name
}
}
Simple examples for string matching operators (contains, notContains, containsi, notContains, startsWith, endsWith)
# contains - returns restaurants whose name contains "Pizzeria"
{
restaurants(filters: { name: { contains: "Pizzeria" } }) {
name
}
}

# notContains - returns restaurants whose name does NOT contain "Pizzeria"
{
restaurants(filters: { name: { notContains: "Pizzeria" } }) {
name
}
}

# containsi - returns restaurants whose name contains "pizzeria" (case‑insensitive)
{
restaurants(filters: { name: { containsi: "pizzeria" } }) {
name
}
}

# notContainsi - returns restaurants whose name does NOT contain "pizzeria" (case‑insensitive)
{
restaurants(filters: { name: { notContainsi: "pizzeria" } }) {
name
}
}

# startsWith - returns restaurants whose name starts with "Pizza"
{
restaurants(filters: { name: { startsWith: "Pizza" } }) {
name
}
}

# endsWith - returns restaurants whose name ends with "Inc"
{
restaurants(filters: { name: { endsWith: "Inc" } }) {
name
}
}
Simple examples for null checks operators (null, notNull)
# null - returns restaurants where description is null
{
restaurants(filters: { description: { null: true } }) {
name
}
}

# notNull - returns restaurants where description is not null
{
restaurants(filters: { description: { notNull: true } }) {
name
}
}
Simple examples for logical operators (and, or, not)
# and - both category must be "pizza" AND averagePrice must be < 20
{
restaurants(filters: {
and: [
{ category: { eq: "pizza" } },
{ averagePrice: { lt: 20 } }
]
}) {
name
}
}

# or - category is "pizza" OR category is "burger"
{
restaurants(filters: {
or: [
{ category: { eq: "pizza" } },
{ category: { eq: "burger" } }
]
}) {
name
}
}

# not - category must NOT be "pizza"
{
restaurants(filters: {
not: { category: { eq: "pizza" } }
}) {
name
}
}
Example with nested logical operators: use and, or, and not to find pizzerias under 20 euros
{
restaurants(
filters: {
and: [
{ not: { averagePrice: { gte: 20 } } }
{
or: [
{ name: { eq: "Pizzeria" } }
{ name: { startsWith: "Pizzeria" } }
]
}
]
}
) {
documentId
name
averagePrice
}
}
Deep filtering with the various APIs

有关如何使用各种 API 进行深度过滤的示例,请参阅 this blog article

排序

🌐 Sorting

查询可以接受带有以下语法的 sort 参数:

🌐 Queries can accept a sort parameter with the following syntax:

  • 根据单个值排序:sort: "value"
  • 根据多个值排序:sort: ["value1", "value2"]

排序顺序可以用 :asc(升序,默认,可省略)或 :desc(降序)来定义。

🌐 The sorting order can be defined with :asc (ascending order, default, can be omitted) or :desc (for descending order).

Example: Fetch and sort on name by ascending order
{
restaurants(sort: "name") {
documentId
name
}
}
Example: Fetch and sort on average price by descending order
{
restaurants(sort: "averagePrice:desc") {
documentId
name
averagePrice
}
}
Example: Fetch and sort on title by ascending order, then on average price by descending order
{
restaurants(sort: ["name:asc", "averagePrice:desc"]) {
documentId
name
averagePrice
}
}

分页

🌐 Pagination

Relay-style 查询可以接受一个pagination参数。结果可以通过页码或偏移量进行分页。

Note

分页方法不能混用。始终要么使用 pagepageSize,要么使用 startlimit

🌐 Pagination methods can not be mixed. Always use either page with pageSize or start with limit.

按页分页

🌐 Pagination by page | 参数 | 描述 | 默认值 || --- | --- | --- || pagination.page | 页码 | 1 || pagination.pageSize | 每页条数 | 10 |

Example query: Pagination by page
{
restaurants_connection(pagination: { page: 1, pageSize: 10 }) {
nodes {
documentId
name
}
pageInfo {
page
pageSize
pageCount
total
}
}
}

按偏移量分页

🌐 Pagination by offset | 参数 | 描述 | 默认值 | 最大值 || --- | --- | --- | --- || pagination.start | 起始值 | 0 | - || pagination.limit | 返回的实体数量 | 10 | -1 |

Example query: Pagination by offset
{
restaurants_connection(pagination: { start: 10, limit: 19 }) {
nodes {
documentId
name
}
pageInfo {
page
pageSize
pageCount
total
}
}
}
Tip

pagination.limit 的默认值和最大值可以在 ./config/plugins.js 文件中通过 graphql.config.defaultLimitgraphql.config.maxLimit 键进行配置。

🌐 The default and maximum values for pagination.limit can be configured in the ./config/plugins.js file with the graphql.config.defaultLimit and graphql.config.maxLimit keys.

locale

[国际化 (i18n)](/cms/features/internationalization) 功能为 GraphQL API 添加了新功能:

🌐 The Internationalization (i18n) feature adds new features to the GraphQL API:

  • 在 GraphQL 模式中添加了 locale 字段。
  • GraphQL 可以用于:
    • 使用 locale 参数查询特定区域的文档
    • 用于针对特定语言环境的文档进行创建更新删除的变更

获取特定区域的所有文档

🌐 Fetch all documents in a specific locale

要获取特定区域的所有文档 ,请将 locale 参数传递给查询:

Example request
query {
restaurants(locale: "fr") {
documentId
name
locale
}
}
Example response
{
"data": {
"restaurants": [
{
"documentId": "a1b2c3d4e5d6f7g8h9i0jkl",
"name": "Restaurant Biscotte",
"locale": "fr"
},
{
"documentId": "m9n8o7p6q5r4s3t2u1v0wxyz",
"name": "Pizzeria Arrivederci",
"locale": "fr"
},
]
}
}

获取特定语言环境的文档

🌐 Fetch a document in a specific locale

要获取特定区域的文档 ,请将 documentIdlocale 参数传递给查询:

示例查询
query Restaurant($documentId: ID!, $locale: I18NLocaleCode) {
restaurant(documentId: "a1b2c3d4e5d6f7g8h9i0jkl", locale: "fr") {
documentId
name
description
locale
}
}
示例响应
{
"data": {
"restaurant": {
"documentId": "lviw819d5htwvga8s3kovdij",
"name": "Restaurant Biscotte",
"description": "Bienvenue au restaurant Biscotte!",
"locale": "fr"
}
}
}

创建一个新的本地化文档

🌐 Create a new localized document

locale 字段可以传递以创建针对特定语言环境的本地化文档 (有关使用 GraphQL 进行变更的更多信息,请参阅 GraphQL API 文档)。

Example: Create a new restaurant for the French locale
mutation CreateRestaurant($data: RestaurantInput!, $locale: I18NLocaleCode) {
createRestaurant(
data: {
name: "Brasserie Bonjour",
description: "Description in French goes here"
},
locale: "fr"
) {
documentId
name
description
locale
}

为特定地区更新文档

🌐 Update a document for a specific locale

可以在变更中传入 locale 参数以更新给定语言环境的文档 (有关使用 GraphQL 的变更的更多信息,请参阅 GraphQL API 文档)。

Example: Update the description field of restaurant for the French locale
mutation UpdateRestaurant($documentId: ID!, $data: RestaurantInput!, $locale: I18NLocaleCode) {
updateRestaurant(
documentId: "a1b2c3d4e5d6f7g8h9i0jkl"
data: {
description: "New description in French"
},
locale: "fr"
) {
documentId
name
description
locale
}

删除文档的语言区域

🌐 Delete a locale for a document

在变更中传递 locale 参数以删除文档的特定本地化

mutation DeleteRestaurant($documentId: ID!, $locale: I18NLocaleCode) {
deleteRestaurant(documentId: "xzmzdo4k0z73t9i68a7yx2kk", locale: "fr") {
documentId
}
}

高级用例

🌐 Advanced use cases

点击以下卡片,查看利用 GraphQL API 和 Strapi 功能的更高级用例的简短指南:

🌐 Click on the following cards for short guides on more advanced use cases leveraging the GraphQL API and Strapi features: