# 在文档服务 API 中使用 publicationFilter

> Source: https://strapi.nodejs.cn/cms/api/document-service/publication-filter

🌐 Document Service API: `publicationFilter`

使用可选的 `publicationFilter` 参数根据文档草稿与已发布版本之间的关系查询文档，例如从未发布的草稿，或自上次发布以来已被修改的条目。它适用于 `findOne()`、`findFirst()`、`findMany()` 和 `count()`，并可与其他查询参数结合使用。`status` 仍然决定你获取的是草稿版本还是已发布版本。

🌐 Use the optional `publicationFilter` parameter to query documents by the relationship between their draft and published versions, for example drafts that were never published, or entries modified since they were last published. It works with `findOne()`, `findFirst()`, `findMany()`, and `count()`, and combines with other query parameters. `status` still decides whether you get the draft or the published version.

`publicationFilter` 是一个参数，与 [status 参数](/cms/api/document-service/status) 结合使用时，可以帮助你通过 [文档服务 API](/cms/api/document-service) 处理复杂查询，以精确找到你需要的内容。

🌐 The `publicationFilter` is a parameter that, combined with [the `status` parameter](/cms/api/document-service/status), can help you cover complex queries to find exactly what you need with the [Document Service API](/cms/api/document-service).

当 `status` 回答“我想要草稿还是已发布的版本？”时，`publicationFilter` 参数回答了一个不同的问题：“我想要哪些文档，基于它们的草稿和已发布版本的关系？” 例如，这对于查找从未发布的草稿，或草稿与在线版本相比有未保存更改的条目非常有用。

🌐 While `status` answers "do I want the draft or the published version?", the `publicationFilter` parameter answers a different question: "which documents do I want, based on how their draft and published versions relate?". This is useful for example to find drafts that were never published, or entries whose draft has unsaved changes compared to what is live.

:::prerequisites

内容类型必须启用[草稿与发布](/cms/features/draft-and-publish)功能。如果草稿与发布被禁用，`publicationFilter`将不起作用。

🌐 The [Draft & Publish](/cms/features/draft-and-publish) feature must be enabled on the content-type. If Draft & Publish is disabled, `publicationFilter` has no effect.

:::

## 可用值 {#values}

🌐 Available values 

`publicationFilter` 接受以下值之一：

| 值 | 选择 |
| --- | --- |
| `never-published` | 从未在特定语言环境中发布的文档 |
| `never-published-document` | 从未在任何语言环境中发布的文档 |
| `modified` | 自上次发布以来草稿被编辑过的文档 |
| `unmodified` | 自上次发布以来草稿未更改的文档 |
| `has-published-version` | 同时拥有草稿和已发布版本的文档 |
| `published-without-draft` | 已发布但没有草稿对应的文档<br/>([仅用于诊断](#diagnostics)) |
| `published-with-draft` | 已发布且同时拥有草稿的文档<br/>([仅用于诊断](#diagnostics)) |
| `has-published-version-document` | 至少在一个语言环境中发布的文档<br/>(在启用 [i18n](/cms/features/internationalization) 时有用) |

有关如何使用 `publicationFilter` 值的详细示例，包括与 `status` 参数一起使用，请参见 [可能的用例](#use-cases) 表。

🌐 For detailed examples of how to use the `publicationFilter` values, including with the `status` parameter, see the [possible use cases](#use-cases) table.

:::note

* 未知值会引发验证错误。
* 以 `-document` 结尾的值会考虑文档的所有语言环境，这在启用 [国际化 (i18n)](/cms/features/internationalization) 时很重要：例如，`never-published-document` 一旦文档的某个语言环境被发布就会将其排除。所有其他值则一次只考虑一个语言环境。在未启用 i18n 的情况下，这两种变体的行为相同。

:::

:::caution Caution: Different default behaviors for different APIs

当省略 `status` 时，文档服务 API 会返回文档的草稿版本，而 REST 和 GraphQL 则会返回已发布的版本，因此 REST API 查询需要明确指定 `status`（参见 [REST API: `publicationFilter`](/cms/api/rest/publication-filter)）。

🌐 The Document Service API returns draft versions of documents when `status` is omitted, while REST and GraphQL return the published ones instead, so REST API queries need an explicit `status` (see [REST API: `publicationFilter`](/cms/api/rest/publication-filter)).

:::

## 可能的使用场景 {#use-cases}

🌐 Possible use cases 

下表列出了许多可能的使用场景，说明如何将 `status` 和 `publicationFilter` 参数结合使用，以在文档服务 API 中精确找到你所需的内容。点击一个使用场景即可跳转到完整示例：

🌐 The following table lists many possible use cases, illustrating how the `status` and `publicationFilter` parameters can be combined to find exactly what you need with the Document Service API. Click a use case to jump to a complete example:

| 我想… | 使用 `status` 作为… | 使用 `publicationFilter` 作为… |
| --- | --- | --- |
| [查找从未发布的草稿](#never-published) | `draft` | `never-published` |
| [查找在任何地区从未发布的草稿](#never-published-document) | `draft` | `never-published-document` |
| [查找已修改的文档](#modified) | `draft` 或 `published` | `modified` |
| [查找未修改的文档](#unmodified) | `draft` 或 `published` | `unmodified` |
| [查找有已发布版本的文档](#has-published-version) | `draft` 或 `published` | `has-published-version` |
| [查找至少在一个地区发布的文档](#has-published-version-document) | `draft` 或 `published` | `has-published-version-document` |
| [与 `findOne()` 和 `findFirst()` 一起使用](#find-one-find-first) | `draft` 或 `published` | 任何值 |
| [只计算匹配的文档](#count) | `draft` 或 `published` | 任何值 |

:::note

将一个值与上表中的相反 `status` 配对是有效的，但不会返回错误，而是返回空结果：例如，`never-published` 与 `status: 'published'` 配对会返回空结果，因为这些文档尚无已发布版本。

🌐 Pairing a value with the opposite `status` from the table above is valid but returns nothing rather than an error: for example, `never-published` with `status: 'published'` returns an empty result, because these documents have no published version yet.

:::

## 例子 {#examples}

🌐 Examples

以下部分列出了上方[表格](#use-cases)中总结的最常见用例。

🌐 The following section lists the most common use cases summed up in the [table](#use-cases) above.

### 查找从未发布的草稿 {#never-published}

🌐 Find never published drafts 

最常见的用例之一是查找从未发布的草稿。为此，请传递 `status: 'draft'` 和 `publicationFilter: 'never-published'`。

🌐 One of the most common use cases is to find the drafts that have never been published. To do so, pass `status: 'draft'` and `publicationFilter: 'never-published'`.

此参数组合仅适用于特定语言环境；要在所有语言环境中查找这些文档，请改为[使用 `never-published-document`](#never-published-document)。

🌐 This parameter combination works only on a given locale; to find these documents across all locales, [use `never-published-document`](#never-published-document) instead.

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回从未在其所在地区发布的草稿。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'never-published',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "New Restaurant",
      publishedAt: null,
      locale: "en", // default locale
      // …
    }
  // …
]
```

### 查找从未在任何地区发布的草稿 {#never-published-document}

🌐 Find drafts never published in any locale 

`publicationFilter: never-published-document` 返回从未在任何地区发布的文档。它查看整个文档的所有地区版本，而不是一次查看一个地区版本。要仅查找给定地区的这些文档，请改用 [使用 `never-published`](#never-published)。

一旦文档的其中一个本地化版本被发布，该文档就算作已发布：文档随后会被排除在外，即使其他本地化版本仅以草稿形式存在。下面的示例返回那些从未在任何地方发布过的文档的草稿版本：

🌐 A document counts as published as soon as one of its locales is published: the document is then left out, even the locales that only exist as a draft. The example below returns the draft versions of documents that were never published anywhere:

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回从未在任何地区发布的文件草稿。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'never-published-document',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "d41r46wac4xix5vpba7561at",
      name: "New Restaurant",
      publishedAt: null,
      locale: "en", // default locale
      // …
    }
  // …
]
```

### 查找已修改的文档 {#modified}

🌐 Find modified documents 

`publicationFilter: modified` 选择草稿有修改但未发布更改的文档。然后 `status` 决定你得到这些文档的哪个版本。

例如，使用 `status: 'draft'` 时，查询返回草稿版本：

🌐 For instance, with `status: 'draft'`, the query returns the draft versions:

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回含有未发布更改的文档草稿版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'modified',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant (updated)",
      publishedAt: null,
      locale: "en", // default locale
      // …
    }
  // …
]
```

<br/>
使用 `status: 'published'` 时，相同的查询会返回这些文档当前的实时版本：

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回具有未发布更改的文档的当前版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'published',
    publicationFilter: 'modified',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: "2024-03-14T15:40:45.330Z",
      locale: "en", // default locale
      // …
    }
  // …
]
```

### 查找未修改的文档 {#unmodified}

🌐 Find unmodified documents 

`publicationFilter: unmodified` 选择自上次发布以来草稿未更改的文档。然后 `status` 决定你将获取这些文档的哪个版本。

例如，使用 `status: 'draft'` 时，查询返回草稿版本：

🌐 For instance, with `status: 'draft'`, the query returns the draft versions:

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回自上次发布以来未更改的文件草稿版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'unmodified',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: null,
      locale: "en", // default locale
      // …
    }
  // …
]
```

<br/>
使用 `status: 'published'` 时，相同的查询会返回这些文档当前的实时版本：

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回自上次发布以来未更改的文档当前版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'published',
    publicationFilter: 'unmodified',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: "2024-03-14T15:40:45.330Z",
      locale: "en", // default locale
      // …
    }
  // …
]
```

### 查找有已发布版本的文档 {#has-published-version}

🌐 Find documents with a published version 

`publicationFilter: has-published-version` 选择那些在相同语言环境下既有草稿版本又有已发布版本的文档。`status` 然后决定你获得这些文档的哪个版本。

例如，使用 `status: 'draft'` 时，查询返回草稿版本：

🌐 For instance, with `status: 'draft'`, the query returns the draft versions:

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回那些在相同语言环境下也有已发布版本的文档草稿版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'has-published-version',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: null,
      locale: "en", // default locale
      // …
    }
  // …
]
```

<br/>
使用 `status: 'published'` 时，相同的查询会返回这些文档当前的实时版本：

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回当前在线版本的文档，这些文档在同一语言区域也有已发布的版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'published',
    publicationFilter: 'has-published-version',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: "2024-03-14T15:40:45.330Z",
      locale: "en", // default locale
      // …
    }
  // …
]
```

### 查找在至少一个地区有已发布版本的文档 {#has-published-version-document}

🌐 Find documents with a published version in at least one locale 

`publicationFilter: has-published-version-document` 会考虑所有地区，因此只要其中一个地区的文档已发布，它就会匹配该文档。使用 `status: 'draft'` 时，它会返回这些文档每个地区的草稿版本，包括那些从未发布过的地区：

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回至少在一个地区发布的文档的草稿版本。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'draft',
    publicationFilter: 'has-published-version-document',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: null,
      locale: "en", // published in at least one locale
      // …
    }
  // …
]
```

### 与 `findOne()` 和 `findFirst()` 一起使用 {#find-one-find-first}

🌐 Use with `findOne()` and `findFirst()` 

如果所请求的文档（以及适用时的区域设置）与筛选条件不匹配，即使 `documentId` 存在，`findOne()` 和 `findFirst()` 也会返回 `null`：

🌐 If the requested document (and locale, when applicable) does not match the filter, `findOne()` and `findFirst()` return `null` even when the `documentId` exists:

#### GET strapi.documents().findOne() — findOne() with publicationFilter: 

Return the document only if it matches the filter, null otherwise.

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findOne({
    documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
    status: 'draft',
    publicationFilter: 'never-published',
});
```

**Response 200 OK:**
```json
null // the documentId exists, but the document does not match never-published
```

### 只计算匹配的文档 {#count}

🌐 Count only matching documents 

没有 `publicationFilter`，`count({ status: 'draft' })` 会计算每一个草稿版本，包括那些文档已经有已发布版本的草稿。添加 `publicationFilter` 以仅计算符合给定值的文档（参见 [`status` 文档](/cms/api/document-service/status#count))：

🌐 Without `publicationFilter`, `count({ status: 'draft' })` counts every draft version, including drafts whose document already has a published version. Add `publicationFilter` to count only the documents that match a given value (see the [`status` documentation](/cms/api/document-service/status#count)):

#### GET strapi.documents().count() — count() with publicationFilter: 

Count only the documents that match a given value.

**JavaScript:**
```
const neverPublishedCount = await strapi
    .documents('api::restaurant.restaurant')
    .count({
      status: 'draft',
      publicationFilter: 'never-published',
    });
```

**Response 200 OK:**
```json
12 // the number of never-published drafts
```

## 诊断值 {#diagnostics}

🌐 Diagnostic values 

`published-without-draft` 和 `published-with-draft` 值仅用于数据完整性检查，而不是日常查询。在健康的数据库中，每个已发布的文档也都有一个草稿版本，因此这些值仅用于检测由遗留数据或手动数据库编辑导致处于不一致状态的文档。它们仅与 `status: 'published'` 一起使用。

🌐 The `published-without-draft` and `published-with-draft` values are meant for data-integrity checks only, not for everyday queries. In a healthy database, every published document also has a draft version, so these values are only useful to detect documents left in an inconsistent state by legacy data or manual database edits. They only work with `status: 'published'`.

<details>
<summary>显示诊断值示例</summary>

`publicationFilter: published-without-draft` 选择没有草稿对应的已发布文档。在正常操作中，这应返回空值：

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回在同一语言环境下没有匹配草稿版本的已发布文档。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'published',
    publicationFilter: 'published-without-draft',
});
```

**Response 200 OK:**
```json
[
  {
    documentId: "j0klm1n2o3p4q5r6s7t8u9v",
    name: "Legacy Restaurant",
    publishedAt: "2024-01-10T09:15:00.000Z",
    locale: "en", // default locale
    // …
  }
  // …
]
```

<br/>
`publicationFilter: published-with-draft` 选择那些也有草稿的已发布文档，这在一个健康的数据库中是每个已发布的文档:

#### GET strapi.documents().findMany() — findMany() with publicationFilter: 

返回那些也有相同本地版本草稿的已发布文档。

**JavaScript:**
```
await strapi.documents('api::restaurant.restaurant').findMany({
    status: 'published',
    publicationFilter: 'published-with-draft',
});
```

**Response 200 OK:**
```json
[
    {
      documentId: "a1b2c3d4e5f6g7h8i9j0klm",
      name: "Biscotte Restaurant",
      publishedAt: "2024-03-14T15:40:45.330Z",
      locale: "en", // default locale
      // …
    }
  // …
]
```

</details>

## 与其他参数的组合 {#combine}

🌐 Combination with other parameters 

`publicationFilter` 与其他查询参数作为逻辑 `AND` 进行组合，包括 [`filters`](/cms/api/document-service/filters) 和 [`populate`](/cms/api/document-service/populate)。在填充 draft 与 publish 关系时，嵌套查询会继承相同的过滤逻辑。

## 内容管理员映射 {#content-manager}

🌐 Content Manager mapping 

在内容管理器中，**草稿（从未发布）** 列表过滤器映射到 `status: 'draft'` 和 `publicationFilter: 'never-published-document'`（以文档为范围，而不是每区域语言的 `never-published`）。

🌐 In the Content Manager, the **Draft (never published)** list filter maps to `status: 'draft'` and `publicationFilter: 'never-published-document'` (document-scoped, not the per-locale `never-published`).
