Skip to content

[Decision] v18:查询能否直接按关联记录的字段筛选(例:「客户行业 = 科技」的商机) #20802

Description

@objectstack-fleet

Ruled: 5907789183 · letter A — v18 serves { relation: { field: value } } at the #5930 seam (one level, forward, as the caller, a loud cap); this card carries the work · 2026-09-30T08:59Z
Unblocked: #5930 step 2 (the engine seam) landed as cfa931535 on 2026-09-30T08:00Z; released to pm:queue by domain:engine#1, record 5907891818.
Blocked-by: #20887

Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) at the maintainer's request 「开一张 v18 的决策卡」. ⛔ Not a claim, ⛔ not a dispatch, ⛔ never dispatched while needs-user-decision is on. Graded: enhancement · priority:p3 · domain:engine · area:api · target:v18.

一句话问题

作者想查「客户行业是科技的商机」,最自然的写法是把条件写在关联字段下面。平台的类型接受这个写法,但数据查询会报 400;而同样的写法放到分析看板里却能查出结果。v18 要真的支持它,还是把这个写法从协议里去掉?

背景

Governing text

协议声明、是否改协议

  • A 改的是 docblock 的描述:从「引擎拒绝」改成「引擎服务」。类型不收窄,属于扩大,Clause-②: no。
  • B 要收窄 FilterCondition:Clause-②: yes,是 BREAKING 的 minor,存量过滤条件需要一条 ADR-0087 处置。

前提(每条带 re-check,均已在 origin/main 96e724475c 跑过)

  1. CRUD 数据口今天拒绝这个写法,点号路径('owner.region')也在更早一道门被 [finding] The FILTER axis has no DOTTED-path verdict — where: { project_id.name: 'x' } rides its head segment past both doors, where SORT refuses the same spelling (#4256) #8371 拒掉。
    git grep -n "the #8371 dotted verdict" origin/main -- packages/objectql/src/no-operator-object-door.ts → 1
  2. 分析看板那一面今天是支持的:cube 过滤把它拍平成点号成员(profile.verified),靠 cube 声明的 join 解析。
    git grep -n "Nested relation (e.g." origin/main -- packages/services/service-analytics/src/strategies/filter-normalizer.ts → 1
  3. 分析的读权限范围那一面拒绝它。
    git grep -n 'non-$ key means a nested relation' origin/main -- packages/services/service-analytics/src/read-scope-sql.ts → 1
  4. 引擎里已有同形的机制:expand 批量加载关联记录,用的就是对关联 id 的 $in 查询。
    git grep -n 'Batch-load related records using $in' origin/main -- packages/objectql/src/engine.ts → 1
  5. 业务拉动(实测):hotcrm 有 4 个 hook 手写同一段两步查询:先查成员行拿到线索 id,再对线索用 id: { $in: leadIds },而且第一步手挑了 top: 5000,超过 5000 条会静默截断。
    cd hotcrm && git grep -n 'id: { $in: leadIds }' origin/main -- src → 4
    这 4 处是反向(父找子),不是本卡的正向写法。hotcrm 的 271 行 filter / where 中,按正则扫描,正向嵌套写法为 0。
    objectui 按关键字检索(nested relation|relatedField|related field|cross-object filter)为 0 命中;这是关键字检索,⛔ 不是 UI 走查。

具体问题

v18 的平台契约里,「按关联记录的字段筛选」要么是服务的能力(A),要么不存在(B)。不裁时,今天的响亮拒绝继续有效,不影响 17.x 发版。

选项 × 真实代价

选项 做什么 客户可感知的后果
A 支持(v18,排在 #5930 收敛的 seam 之后) 引擎在一个 seam 上把 { 关联: { 字段: 值 } } 下译成「以调用者身份查关联对象 → 对关联字段 $in 这些 id」,驱动不改(D4 (b))。首版只做一层、只做正向(子 → 父)。多值关联按「任一匹配」处理。 列表视图、API、AI 写的查询都能直接写「客户行业 = 科技」。CRUD 与看板对同一写法给同一个答案。多一次内部查询;关联集合很大时按上限响亮拒绝,⛔ 不截断。
B 退役(v18 收窄类型) FilterCondition 不再接受这个写法,在发布、保存时就报错,只剩「两步 + $in」一条路。分析看板的嵌套写法同时退役,点号成员写法保留。 作者和 AI 在保存时就被拦下,不用等到运行时。但这个能力要靠手写两步查询,像 hotcrm 那 4 个 hook 一样,会重复写、会截断。

业务含义直译

  • A = 像 Salesforce 那样,列表筛选可以直接写「客户.行业 = 科技」。平台替你做两步查询,并且按你的权限做。
  • B = 平台明说「不能跨对象筛选」,想做就在代码里自己先查一遍。像早期只支持单表筛选的轻量表格工具。

四轴论证(从业务立场)

os-decision-facets

Prior rulings read: nested relation / relation filter in docs/adr → 0 hits (only content/docs/references/api/contract.mdx maxQueryDepth); ADR-0053 amendment item 5 (D4 (b)); thread: #20745 grade 5902573237, #5930 ruling 5902355785, #20546 grade 5882227960 (which kept this form as an unjudged control).

推荐

推荐 A:v18 支持,排在 #5930 收敛落地 seam 之后;首版一层、正向、以调用者读权限执行、超上限响亮拒绝。

裁后执行(维护者只裁方向)

相关单与 PR

#20745(已关,PR #20781)· #20546 / PR #20744 · #5930(v18 过滤器收敛,裁决 5902355785)· #20782(skill 教 $in)· #8371(点号路径拒绝)· ADR-0053 修订第 5 条 · ADR-0049 · ADR-0087

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions