Skip to content

driver-memory analytics 面:同一字段上的多个算子互相覆盖,{qty: {$gte:150, $lte:250}} 只剩最后一个 —— 区间塌成单边,结果被放大 #5440

Description

@os-zhuang

#5374($notContains 编译成裸 {$not: 'x'})时,为了确认修复没有把 $match 的组装弄坏,逐个实测了「一个 where 里同一字段带多个算子」会编译成什么。这一条不属于 #5374 的范围面 —— #5374 裁的是算子 → 谓词这一层(映射指向了错的目标),这一条在谓词 → $match 的组装这一层,#5374 修好之后依然完整存在。按 Prime Directive #10 单独记在这里,unassigned。

位置

packages/plugins/driver-memory/src/memory-analytics.ts,query() Stage 1 的 $match 组装循环(约 :180):

for (const filter of normalizedFilters) {
  const fieldPath = this.resolveFieldPath(cube, filter.member);
  matchStage[fieldPath] = /* 该条目的谓词 */;   // ← 直接赋值,不合并
}

flattenFilterCondition{field: {$op1: a, $op2: b}} 会 push 两条 NormalizedCubeFilter,member 都是 field。两条都以 matchStage[fieldPath] = … 落盘,于是后一条覆盖前一条,前一个算子彻底消失。

现象(实测)

3 行数据,qty 分别为 100 / 200 / 300(id 分别为 1/2/3)。左列是 find(),右列是 analytics 面 —— 两列都是在 #5374 修复之后测的,即这条与那条无关:

where find() analytics 实际编译出的 $match
{qty: {$gte: 150, $lte: 250}} [2] [1,2] {qty: {$lt: 250}}
{qty: {$ne: 300, $gt: 150}} [2] [2,3] {qty: {$gt: 150}}

方向是放大:丢掉的永远是一个约束,所以行只会变多,不会变少。这与 #5345 / #5373 / #5374 是同一个方向、同一类后果 —— 一个看起来正常的图表统计了它本该排除的行 —— 只是机制换成了「谓词被生成了,但被下一个谓词覆盖掉」。

为什么是 bug

  1. {$gte, $lte} 是区间的规范写法。 AnalyticsQuery.whereFilterCondition,而 dashboard widget 元数据直接用这个形状表达「金额在某区间」「日期在某窗口」。这恰恰是最常见的多算子写法,不是边角。
  2. declared ≠ enforced。 ANALYTICS_FILTER_CAPABILITIES 声明本面支持这 11 个算子,assertFilterConditionShape 也放行了 {$gte, $lte} 这个形状 —— 声明能算,实际只算了一半。
  3. 另一半是对的。 live query path 的 normalizeFieldOperators 把同字段的多个算子合并进一个对象,多个 regex 型算子还会通过 _multiRegex 提升成 $and。所以这是同一个 driver 的两面对同一个 where 给出不同行集 —— { field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FILTER、formula/driver-memory FALSE #5240 为本包立下的不变量所禁止的形状。

建议(不代裁决)

不是一行改。合并本身容易(matchStage[fieldPath] = {...existing, ...predicate}),但有两处必须一起想清楚,否则会把一个覆盖换成另一个覆盖:

另一条路是拒收同字段多算子(与 #5345 同款),但那会拒掉本面 find() 明明能算、且是 widget 常用形状的查询,恐怕不是想要的答案。

未验证的部分

关联:#5374(同文件、同一轮核对里发现;它裁的是算子→谓词层,本条是谓词→$match 组装层)、#5345#5373#5240(本包两面不得分叉)、#3948(no-silent-drop)。

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions