You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while implementing #4708 (packages/services/service-analytics/src/dataset-executor.ts); unrelated to that fix, so filed rather than fixed in it.
Mechanism
mergeByDimensions is the seam every multi-query dataset result is assembled through — supplementary measure-scoped queries and the compareTo pass both merge back onto the grid with it. Its key function:
null and '' collapse.String(row[d] ?? '') maps a genuinely null dimension value and an empty-string one onto the same key, merging "unassigned" into "blank".
The neighbouring cross-object-rebucket.ts already solved exactly this and documents why:
// JSON-encoded, so the empty bucket (`null` on both aggregation paths since// …) … `"null"` — plain interpolation renders both as `null` and would merge twofor(constfofbaseDimFields)keyParts.push(`${f}=${JSON.stringify(row[f]??null)}`);
So the repo has the right pattern one file over; mergeByDimensions predates it.
Impact
Only bites datasets grouped by two or more dimensions where the concatenation of adjacent values is ambiguous — a matrix report by region × segment, owner × stage, or any pair of free-text/select values. Single-dimension grids (the common case) are unaffected, which is presumably why it has survived. When it does bite, it is silent: the grid keeps the right number of columns and a plausible number of rows.
Suggested direction
Key the same way cross-object-rebucket does — dimensions.map((d) => ${d}=${JSON.stringify(row[d] ?? null)}).join('&') — which fixes both the delimiter and the null/empty-string conflation in one change. Needs a test with a colliding pair ('ab'|'c' vs 'a'|'bc') and one with a null-vs-empty dimension value.
Note the fix changes only the internal join key, never a value in the response, so it is contained.
Found while implementing #4708 (
packages/services/service-analytics/src/dataset-executor.ts); unrelated to that fix, so filed rather than fixed in it.Mechanism
mergeByDimensionsis the seam every multi-query dataset result is assembled through — supplementary measure-scoped queries and thecompareTopass both merge back onto the grid with it. Its key function:Two problems in one line:
{ region: 'ab', segment: 'c' }and{ region: 'a', segment: 'bc' }both key as"abc", so the second row's measures are merged onto the first — one row silently absorbs another group's numbers, and the other group's measure column is left absent (which then renders blank, or gets an empty-group0filled into it after A filtered dataset measure returns ABSENT (not 0) for a group its filter excludes, so every derived ratio over it blanks — on exactly the worst-performing row #4708).nulland''collapse.String(row[d] ?? '')maps a genuinely null dimension value and an empty-string one onto the same key, merging "unassigned" into "blank".The neighbouring
cross-object-rebucket.tsalready solved exactly this and documents why:So the repo has the right pattern one file over;
mergeByDimensionspredates it.Impact
Only bites datasets grouped by two or more dimensions where the concatenation of adjacent values is ambiguous — a matrix report by
region×segment,owner×stage, or any pair of free-text/selectvalues. Single-dimension grids (the common case) are unaffected, which is presumably why it has survived. When it does bite, it is silent: the grid keeps the right number of columns and a plausible number of rows.Suggested direction
Key the same way
cross-object-rebucketdoes —dimensions.map((d) =>${d}=${JSON.stringify(row[d] ?? null)}).join('&')— which fixes both the delimiter and the null/empty-string conflation in one change. Needs a test with a colliding pair ('ab'|'c'vs'a'|'bc') and one with a null-vs-empty dimension value.Note the fix changes only the internal join key, never a value in the response, so it is contained.
Related: #4708.