> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pubrio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AND / OR 操作符

> 为任意多值筛选器覆盖默认 AND/OR 操作符 — 完整参考及可复制示例。

`filter_conditions` 是请求体中的一个可选数组。每条记录将一个多值筛选器从默认的 OR("匹配任一")行为升级为 AND("匹配全部"),或反之。未列出的筛选器保持默认。

## 结构

<CodeGroup>
  ```json JSON theme={null}
  {
    "filter_conditions": [
      { "key": "technologies", "operator": "and" },
      { "key": "verticals",    "operator": "or"  }
    ]
  }
  ```

  ```typescript TypeScript theme={null}
  type FilterCondition = {
    /** 要覆盖的筛选键。见下文“支持的键”。 */
    key: string;
    /** 不区分大小写: "and" | "or"。数组默认为 "or"。 */
    operator: "and" | "or";
  };

  type SearchRequest = {
    // …其他所有筛选器…
    filter_conditions?: FilterCondition[];
  };
  ```
</CodeGroup>

<Note>
  每条记录的 `key` 和 `operator` 都是必填项。仅含 `operator` 的记录会被静默忽略 — 没有"全局覆盖"开关。
</Note>

***

## 为什么重要

默认操作符是 OR,因为多数潜客挖掘工作流都需要广覆盖:"位于*任何*这些国家的人"、"标签包含*任何*这些垂直的公司"。但当目标是高精度时 — "*同时*使用 `Salesforce` + `HubSpot` + `Marketo`" — 你需要 AND。

写错操作符的代价:

* **想要 AND 却用了 OR:** 响应过度召回 — 你会看到只命中一个标签的公司,而不是整个组合。容易发现,影响结果质量。
* **想要 OR 却用了 AND:** 响应召回不足 — 多值 AND 筛选通常返回近零行,因为现实中的数组很少同时包含所有请求值。容易发现,看起来像查询出错。

底层上,引擎会把你选择的操作符编译为原生 Postgres 数组操作符:OR 用 `&&`(重叠),AND 用 `@>`(包含)。两者都对索引友好,所以差异主要在*结果数*,而不是查询时延。

***

## 支持的键

具体支持的键集取决于你调用的端点:

| 键                                        | `/companies/search` | `/people/search` | `/companies/advertisements/search` | 默认 | `and` 的含义       |
| ---------------------------------------- | ------------------- | ---------------- | ---------------------------------- | -- | --------------- |
| `technologies`                           | ✓                   | ✓                | —                                  | OR | 拥有列表中所有技术       |
| `categories`                             | ✓                   | ✓                | —                                  | OR | 标签包含全部类目        |
| `verticals`                              | ✓                   | ✓                | —                                  | OR | 属于全部垂直          |
| `vertical_categories`                    | ✓                   | ✓                | —                                  | OR | 属于全部垂直类目        |
| `vertical_sub_categories`                | ✓                   | ✓                | —                                  | OR | 属于全部垂直子类目       |
| `keywords`                               | ✓                   | ✓                | —                                  | OR | 描述包含全部关键词       |
| `places`                                 | ✓                   | ✓                | —                                  | OR | 位于列表中所有地点       |
| `exclude_places`                         | ✓                   | ✓                | —                                  | OR | 排除列表中所有地点       |
| `advertisement_target_locations`         | ✓                   | —                | —                                  | OR | 广告投放至全部国家(公司端点) |
| `advertisement_exclude_target_locations` | ✓                   | —                | —                                  | OR | 广告排除全部国家        |
| `advertisement_search_terms`             | ✓                   | —                | —                                  | OR | 广告文案包含全部词       |
| `job_exclude_locations`                  | ✓                   | —                | —                                  | OR | 招聘岗位排除全部地点      |
| `social_media`                           | —                   | ✓                | —                                  | OR | 拥有所有列出的社交账号     |
| `target_locations`                       | —                   | —                | ✓                                  | OR | 广告投放至全部国家(广告端点) |
| `exclude_target_locations`               | —                   | —                | ✓                                  | OR | 广告排除全部国家        |

<Tip>
  上述键映射 OpenAPI 中各 `*_filter_conditions` 模式的 `enum` 数组(`company_filter_conditions`、`people_filter_conditions`、`ads_filter_conditions`)。在某个端点上发送不支持的键会被静默忽略。
</Tip>

***

## 配方

<Tabs>
  <Tab title="同时使用全部技术(公司)">
    **目标:** *同时*使用 Python、PostgreSQL、Kubernetes 的公司 — 而不是只用其中一个。

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "technologies": [37, 152, 408],
          "filter_conditions": [
            { "key": "technologies", "operator": "and" }
          ],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "technologies": [37, 152, 408],
              "filter_conditions": [
                  { "key": "technologies", "operator": "and" }
              ],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          technologies: [37, 152, 408],
          filter_conditions: [
            { key: "technologies", operator: "and" }
          ],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>

    去掉 `filter_conditions` 那条记录,搜索范围会扩展到三者*中任意一个*。
  </Tab>

  <Tab title="任一位置 + 排除">
    **目标:** 位于美国、加拿大、英国*任一国家*,但不在旧金山的公司。

    OR 已经是 `locations` 的默认行为,所以无需显式声明。`exclude_places` 独立处理负向筛选 — 也不需要覆盖。

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "locations": ["US", "CA", "GB"],
          "exclude_places": ["San Francisco"],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "locations": ["US", "CA", "GB"],
              "exclude_places": ["San Francisco"],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          locations: ["US", "CA", "GB"],
          exclude_places: ["San Francisco"],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>
  </Tab>

  <Tab title="多区域广告活动">
    **目标:** *同时*投放欧盟和美国的广告(多区域活动)— 不是单一市场广告。使用专用的 `ads_filter_conditions` 模式中的 `target_locations` 键。

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/companies/advertisements/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "target_locations": ["US", "DE", "FR"],
          "filter_conditions": [
            { "key": "target_locations", "operator": "and" }
          ],
          "start_dates": ["2026-01-01"],
          "end_dates":   ["2026-04-22"],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/companies/advertisements/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "target_locations": ["US", "DE", "FR"],
              "filter_conditions": [
                  { "key": "target_locations", "operator": "and" }
              ],
              "start_dates": ["2026-01-01"],
              "end_dates":   ["2026-04-22"],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/companies/advertisements/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          target_locations: ["US", "DE", "FR"],
          filter_conditions: [
            { key: "target_locations", operator: "and" }
          ],
          start_dates: ["2026-01-01"],
          end_dates:   ["2026-04-22"],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>

    <Note>
      广告端点使用自有的 `ads_filter_conditions` 模式(键集较小:`target_locations`、`exclude_target_locations`)。可在 `/companies/search` 与 `/people/search` 上使用的覆盖键在此*不适用*。
    </Note>
  </Tab>

  <Tab title="多技术栈公司中的人员">
    **目标:** 任职于*同时*安装了 Salesforce 和 HubSpot 的公司的人员 — 经典的 CRM 替换信号。展示统一引擎:相同的 `technologies` 键、相同的操作符,但用在 `/people/search`。

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.pubrio.com/people/search \
        -H "Content-Type: application/json" \
        -H "pubrio-api-key: YOUR_API_KEY" \
        -d '{
          "people_titles": ["RevOps", "Sales Operations"],
          "technologies": [114, 287],
          "filter_conditions": [
            { "key": "technologies", "operator": "and" }
          ],
          "per_page": 25,
          "page": 1
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.pubrio.com/people/search",
          headers={
              "Content-Type": "application/json",
              "pubrio-api-key": "YOUR_API_KEY",
          },
          json={
              "people_titles": ["RevOps", "Sales Operations"],
              "technologies": [114, 287],
              "filter_conditions": [
                  { "key": "technologies", "operator": "and" }
              ],
              "per_page": 25,
              "page": 1,
          },
      )
      print(response.json())
      ```

      ```javascript Node.js theme={null}
      const response = await fetch("https://api.pubrio.com/people/search", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({
          people_titles: ["RevOps", "Sales Operations"],
          technologies: [114, 287],
          filter_conditions: [
            { key: "technologies", operator: "and" }
          ],
          per_page: 25,
          page: 1,
        }),
      });
      console.log(await response.json());
      ```
    </CodeGroup>
  </Tab>
</Tabs>

***

## 常见错误

<AccordionGroup>
  <Accordion title="忘了 key,只发了 operator" icon="circle-xmark">
    没有"全局默认操作符"开关。每条记录都必须指定具体的筛选器:

    ```json theme={null}
    // 被忽略 — 没有 key
    { "filter_conditions": [{ "operator": "and" }] }

    // 正确 — 仅覆盖 technologies 筛选器
    { "filter_conditions": [{ "key": "technologies", "operator": "and" }] }
    ```
  </Accordion>

  <Accordion title="以为多条记录会组合" icon="circle-xmark">
    每条记录都是相互独立的按键覆盖 — 不会相互链式组合。同时列出 `technologies` 和 `verticals` 不会在二者之间形成布尔表达式;每条只是设置自己那个数组的操作符。

    *跨筛选键*的组合方式始终是 AND(每个筛选器都必须命中)。无法通过 `filter_conditions` 让两个不同的筛选维度做 OR 组合。如果需要真正的"不同筛选器之间 OR"搜索,请发起两次请求并在客户端合并结果。
  </Accordion>

  <Accordion title="在长数组上使用 AND" icon="triangle-exclamation">
    AND 是 `column @> ARRAY[…]` — 所有值都必须存在。一旦数组超过 8 个元素,几乎总会返回零行,因为现实中的标签很稀疏。AND 覆盖的数组保持在 2-4 个值;探索性或类目级筛选用 OR。
  </Accordion>

  <Accordion title="在 /people/search 公司筛选上写错键" icon="circle-xmark">
    在 `/people/search` 中,人员 API 的字段名是 `company_places` / `company_locations`。但在 `filter_conditions[].key` 内部必须使用**引擎名** — `places`、`locations`。重映射在引擎读取 `filter_conditions` 之前已完成。

    ```json theme={null}
    // 不会生效 — 引擎不把 "company_places" 视为筛选键
    { "filter_conditions": [{ "key": "company_places", "operator": "and" }] }

    // 正确
    { "filter_conditions": [{ "key": "places", "operator": "and" }] }
    ```

    完整的重映射表见 [人员 + 公司筛选器](/cn/developer-guides/filters/people-with-company-filters#key-remap-reference) 页面。
  </Accordion>
</AccordionGroup>

<Tip>
  拿不准时,先省略 `filter_conditions`,再对照预期检查结果数。只为默认行为不符合意图的筛选器添加覆盖 — 这能让请求体更小、更易调试。
</Tip>

***

## 另请参阅

<CardGroup cols={2}>
  <Card title="筛选器概览" icon="filter" href="/cn/developer-guides/filters/overview">
    心智模型 — 如果 `filter_conditions` 是你的第一站,请从这里开始。
  </Card>

  <Card title="人员 + 公司筛选器" icon="users-rectangle" href="/cn/developer-guides/filters/people-with-company-filters">
    如何在 `/people/search` 上叠加公司筛选,包括键的重映射。
  </Card>

  <Card title="公司搜索参考" icon="building" href="/cn/api-reference/endpoint/companies/search">
    `/companies/search` 的完整请求结构(包含 `company_filter_conditions`)。
  </Card>

  <Card title="人员搜索参考" icon="user" href="/cn/api-reference/endpoint/people/search">
    `/people/search` 的完整请求结构(包含 `people_filter_conditions`)。
  </Card>
</CardGroup>
