diff --git a/pkg/tsdb/elasticsearch/response_parser.go b/pkg/tsdb/elasticsearch/response_parser.go index 73c5ca34f4b..9225cbada1f 100644 --- a/pkg/tsdb/elasticsearch/response_parser.go +++ b/pkg/tsdb/elasticsearch/response_parser.go @@ -665,7 +665,7 @@ func processAggregationDocs(esAgg *simplejson.Json, aggDef *BucketAgg, target *Q queryResult *backend.DataResponse, props map[string]string) error { propKeys := createPropKeys(props) frames := data.Frames{} - fields := createFieldsFromPropKeys(queryResult.Frames, propKeys) + fields := createFields(queryResult.Frames, propKeys) for _, v := range esAgg.Get("buckets").MustArray() { bucket := simplejson.NewFromAny(v) @@ -675,7 +675,8 @@ func processAggregationDocs(esAgg *simplejson.Json, aggDef *BucketAgg, target *Q for _, field := range fields { for _, propKey := range propKeys { if field.Name == propKey { - field.Append(props[propKey]) + value := props[propKey] + field.Append(&value) } } if field.Name == aggDef.Field { @@ -1134,9 +1135,15 @@ func setSearchWords(frame *data.Frame, searchWords map[string]bool) { } } -func createFieldsFromPropKeys(frames data.Frames, propKeys []string) []*data.Field { +func createFields(frames data.Frames, propKeys []string) []*data.Field { var fields []*data.Field - if frames == nil { + // Otherwise use the fields from frames + if frames != nil { + for _, frame := range frames { + fields = append(fields, frame.Fields...) + } + // If we have no frames, we create fields from propKeys + } else { for _, propKey := range propKeys { fields = append(fields, data.NewField(propKey, nil, []*string{})) } diff --git a/pkg/tsdb/elasticsearch/response_parser_test.go b/pkg/tsdb/elasticsearch/response_parser_test.go index 56414a61b2f..7592a356eb9 100644 --- a/pkg/tsdb/elasticsearch/response_parser_test.go +++ b/pkg/tsdb/elasticsearch/response_parser_test.go @@ -1472,14 +1472,14 @@ func TestResponseParser(t *testing.T) { require.Len(t, result.response.Responses, 1) frames := result.response.Responses["A"].Frames - require.True(t, len(frames) > 0) // FIXME + require.True(t, len(frames) > 0) for _, field := range frames[0].Fields { trueValue := true filterableConfig := data.FieldConfig{Filterable: &trueValue} // we need to test that the only changed setting is `filterable` - require.Equal(t, filterableConfig, *field.Config) // FIXME + require.Equal(t, filterableConfig, *field.Config) } }) }) @@ -1641,6 +1641,92 @@ func TestResponseParser(t *testing.T) { requireFloatAt(t, 2, f3, 0) requireFloatAt(t, 2, f3, 1) }) + + t.Run("With max and multiple terms agg", func(t *testing.T) { + targets := map[string]string{ + "A": `{ + "metrics": [ + { + "type": "max", + "field": "counter", + "id": "1" + } + ], + "bucketAggs": [{ "type": "terms", "field": "label", "id": "2" }, { "type": "terms", "field": "level", "id": "3" }] + }`, + } + response := `{ + "responses": [{ + "aggregations": { + "2": { + "buckets": [ + { + "key": "val3", + "3": { + "buckets": [ + { "key": "info", "1": { "value": "299" } }, { "key": "error", "1": {"value": "300"} } + ] + } + }, + { + "key": "val2", + "3": { + "buckets": [ + {"key": "info", "1": {"value": "300"}}, {"key": "error", "1": {"value": "298"} } + ] + } + }, + { + "key": "val1", + "3": { + "buckets": [ + {"key": "info", "1": {"value": "299"}}, {"key": "error", "1": {"value": "296"} } + ] + } + } + ] + } + } + }] + }` + + result, err := parseTestResponse(targets, response) + assert.Nil(t, err) + assert.Len(t, result.Responses, 1) + frames := result.Responses["A"].Frames + require.Len(t, frames, 1) + requireFrameLength(t, frames[0], 6) + require.Len(t, frames[0].Fields, 3) + + f1 := frames[0].Fields[0] + f2 := frames[0].Fields[1] + f3 := frames[0].Fields[2] + + require.Equal(t, "label", f1.Name) + require.Equal(t, "level", f2.Name) + require.Equal(t, "Max", f3.Name) + + requireStringAt(t, "val3", f1, 0) + requireStringAt(t, "val3", f1, 1) + requireStringAt(t, "val2", f1, 2) + requireStringAt(t, "val2", f1, 3) + requireStringAt(t, "val1", f1, 4) + requireStringAt(t, "val1", f1, 5) + + requireStringAt(t, "info", f2, 0) + requireStringAt(t, "error", f2, 1) + requireStringAt(t, "info", f2, 2) + requireStringAt(t, "error", f2, 3) + requireStringAt(t, "info", f2, 4) + requireStringAt(t, "error", f2, 5) + + requireFloatAt(t, 299, f3, 0) + requireFloatAt(t, 300, f3, 1) + requireFloatAt(t, 300, f3, 2) + requireFloatAt(t, 298, f3, 3) + requireFloatAt(t, 299, f3, 4) + requireFloatAt(t, 296, f3, 5) + }) } func parseTestResponse(tsdbQueries map[string]string, responseBody string) (*backend.QueryDataResponse, error) {