diff --git a/packages/grafana-data/src/transformations/transformers/groupBy.test.ts b/packages/grafana-data/src/transformations/transformers/groupBy.test.ts index 337de2f9b26..76e420f61f6 100644 --- a/packages/grafana-data/src/transformations/transformers/groupBy.test.ts +++ b/packages/grafana-data/src/transformations/transformers/groupBy.test.ts @@ -260,4 +260,50 @@ describe('GroupBy transformer', () => { expect(result[1].fields).toEqual(expectedB); }); }); + + it('should group values and keep the order of the fields', async () => { + const testSeries = toDataFrame({ + name: 'A', + fields: [ + { name: 'message', type: FieldType.string, values: ['500', '404', '404', 'one', 'one', 'two', '200'] }, + { name: 'values', type: FieldType.number, values: [1, 2, 2, 3, 3, 3, 4] }, + ], + }); + + const cfg: DataTransformerConfig = { + id: DataTransformerID.groupBy, + options: { + fields: { + message: { + operation: GroupByOperationID.groupBy, + aggregations: [], + }, + values: { + operation: GroupByOperationID.aggregate, + aggregations: [ReducerID.sum], + }, + }, + }, + }; + + await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith((received) => { + const result = received[0]; + const expected: Field[] = [ + { + name: 'message', + type: FieldType.string, + values: new ArrayVector(['500', '404', 'one', 'two', '200']), + config: {}, + }, + { + name: 'values (sum)', + type: FieldType.number, + values: new ArrayVector([1, 4, 6, 3, 4]), + config: {}, + }, + ]; + + expect(result[0].fields).toEqual(expected); + }); + }); }); diff --git a/packages/grafana-data/src/transformations/transformers/groupBy.ts b/packages/grafana-data/src/transformations/transformers/groupBy.ts index ae70dbab820..be1763833d2 100644 --- a/packages/grafana-data/src/transformations/transformers/groupBy.ts +++ b/packages/grafana-data/src/transformations/transformers/groupBy.ts @@ -63,13 +63,13 @@ export const groupByTransformer: DataTransformerInfo // Group the values by fields and groups so we can get all values for a // group for a given field. - const valuesByGroupKey: Record> = {}; + const valuesByGroupKey = new Map>(); for (let rowIndex = 0; rowIndex < frame.length; rowIndex++) { const groupKey = String(groupByFields.map((field) => field.values.get(rowIndex))); - const valuesByField = valuesByGroupKey[groupKey] ?? {}; + const valuesByField = valuesByGroupKey.get(groupKey) ?? {}; - if (!valuesByGroupKey[groupKey]) { - valuesByGroupKey[groupKey] = valuesByField; + if (!valuesByGroupKey.has(groupKey)) { + valuesByGroupKey.set(groupKey, valuesByField); } for (let field of frame.fields) { @@ -89,16 +89,14 @@ export const groupByTransformer: DataTransformerInfo } const fields: Field[] = []; - const groupKeys = Object.keys(valuesByGroupKey); for (const field of groupByFields) { const values = new ArrayVector(); const fieldName = getFieldDisplayName(field); - for (let key of groupKeys) { - const valuesByField = valuesByGroupKey[key]; - values.add(valuesByField[fieldName].values.get(0)); - } + valuesByGroupKey.forEach((value) => { + values.add(value[fieldName].values.get(0)); + }); fields.push({ name: field.name, @@ -120,8 +118,8 @@ export const groupByTransformer: DataTransformerInfo const aggregations = options.fields[fieldName].aggregations; const valuesByAggregation: Record = {}; - for (const groupKey of groupKeys) { - const fieldWithValuesForGroup = valuesByGroupKey[groupKey][fieldName]; + valuesByGroupKey.forEach((value) => { + const fieldWithValuesForGroup = value[fieldName]; const results = reduceField({ field: fieldWithValuesForGroup, reducers: aggregations, @@ -133,7 +131,7 @@ export const groupByTransformer: DataTransformerInfo } valuesByAggregation[aggregation].push(results[aggregation]); } - } + }); for (const aggregation of aggregations) { const aggregationField: Field = { @@ -150,7 +148,7 @@ export const groupByTransformer: DataTransformerInfo processed.push({ fields, - length: groupKeys.length, + length: valuesByGroupKey.size, }); }