Skip to content

analytics: 只用来限定「日期区间」的 timeDimension 被补上默认 dateGranularity,于是网格被静默按月拆分 —— 「按 Owner 统计」加个日期筛选就变成「按 Owner × 月」 #5688

Description

@os-zhuang

立单于 #5537 的实施过程(PR 见该单)。#5537 的 fields 装配无关:下面的复现跑在 #5537 从未影响的那条「无 measure filter 单查询」路径上,且在 origin/main(c36abfe98,含 #5587/#5634/#5667)与 #5537 的分支上逐字节同样复现。范围外,单独立单。

现象

一个 dataset selection 只把日期维度用作窗口timeDimensions: [{ dimension, dateRange }],不带 granularity,也把它列进 selection.dimensions)——这正是 dashboard 日期区间筛选器的产物,executor 自己的注释就把它称作 "a dashboard date-range filter is the usual source"——结果网格却额外按该日期维度分桶:多出一列没人选过的时间列,行数按月裂开。

复现

dataset(关键条件:日期维度声明了显式 dateGranularity):

dimensions:
  - { name: owner,      field: owner_id,   type: lookup, label: Owner }
  - { name: close_date, field: close_date, type: date,   label: Close Date, dateGranularity: month }
measures:
  - { name: opp_count,  aggregate: count,  label: Opps }

三条数据:u1 @2026-01u1 @2026-02u2 @2026-01

selection —— 只按 owner 分组,日期只当窗口:

{ dimensions: ['owner'],
  measures: ['opp_count'],
  timeDimensions: [{ dimension: 'close_date', dateRange: ['2026-01-01', '2026-02-28'] }] }

实测响应:

fields [{"name":"owner","type":"string","label":"Owner"},
        {"name":"close_date","type":"time"},          <-- 没人选过这一列
        {"name":"opp_count","type":"number","label":"Opps"}]
rows   [{"owner":"u1","close_date":"2026-01","opp_count":1},
        {"owner":"u1","close_date":"2026-02","opp_count":1},   <-- u1 被拆成两行
        {"owner":"u2","close_date":"2026-01","opp_count":1}]

期望:2 行(u1: 2u2: 1),fieldsowner + opp_count

落点

packages/services/service-analytics/src/dataset-executor.ts buildQuery(origin/main c36abfe L888-L909):

const resolvedTimeDims = selTimeDims.map((t) => {
  if (t.granularity) return t;
  const granularity = granularityFor(t.dimension);   // L899
  return granularity ? { ...t, granularity } : t;
});

granularityForresolveDimensionGranularity(selection, name, datasetDefault)datasetDefault 即「dataset 显式声明过 dateGranularity」时编译出的单元素 cube.granularities。于是一个只有 dateRange 的条目被补上 granularity: 'month';而一旦条目带上 granularity,它就是 GROUP BY 项、并且按 #4033projectedDimensionsobjectql-strategy.ts L1130,native 侧同义)投影成结果列。

这条补默认值本身是刻意的buildQuery 上方的长注释写明了理由:compareTo 需要的正是「窗口条目不得抑制分桶」,否则主网格按月、比较网格按原始时间戳,两边维度键对不上,每个 compare 列都空。所以两种需求在同一处打架:

判据看起来应该是「这个 dimension 是否出现在 selection.dimensions(或调用方自己写了 granularity)」,但这属于会改变响应形状的契约取舍,不该由我在 #5537 里顺手猜,故立单。

触发条件与影响面

必要条件(三者同时):dataset 的该日期维度声明了显式 dateGranularity;selection 的 timeDimensions 条目granularityselection.dateGranularity 未设。HotCRM 一类 dataset 普遍声明 dateGranularity,dashboard 的日期区间筛选器又普遍只发 dateRange,因此可达性不低。

命中时是行数与列集都变(不是纯元数据问题):一个「Won by Owner」表加上日期筛选后每人一行变成每人每月一行,KPI 单值卡会拿到多行里的第一行。

附带的次要症状(同一根因,同一条路径):这样投影出来的时间列在 fields 里只有 type 没有 label —— analytics-service.ts 的维度 label 富化(L915 起)只遍历 selection.dimensions,看不到只在 timeDimensions 里的列。#5537 的 PR 把这一点当作两条路径一致的既有行为钉住了(dataset-dimension-field-descriptors.test.ts 里成对的控制用例),并明确指向本单。

不重复

已搜:timeDimensions dateGranularity(命中 #3650/#3777,均已关闭且是另一件事:前者是 dateRange 被忽略,后者是上界打在 datetime 列上)、dataset-executor buildQuery groupingdateRange granularity bucket dashboard widget rowsdate range filter extra column group by month widget —— 无 open 重复。

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