diff --git a/public/app/plugins/datasource/elasticsearch/bucketAgg.js b/public/app/plugins/datasource/elasticsearch/bucketAgg.js index f4abdd35a00..a7852792e90 100644 --- a/public/app/plugins/datasource/elasticsearch/bucketAgg.js +++ b/public/app/plugins/datasource/elasticsearch/bucketAgg.js @@ -65,7 +65,7 @@ function (angular, _, $) { $scope.orderByOptions = [ {text: "Doc Count", value: '_count' }, {text: "Term name", value: '_term' }, - {text: "Average of @value", value: '0' }, + {text: "Average of @value", value: 'm0' }, ]; } @@ -78,7 +78,11 @@ function (angular, _, $) { addIndex - 1; } - bucketAggs.splice(addIndex, 0, {type: "terms", field: "select field" }); + var id = _.reduce($scope.target.bucketAggs.concat($scope.target.metrics), function(max, val) { + return parseInt(val.id) > max ? parseInt(val.id) : max; + }, 0); + + bucketAggs.splice(addIndex, 0, {type: "terms", field: "select field", id: (id+1).toString()}); }; $scope.removeBucketAgg = function() { diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index 94eba54f8b5..7622fa243c0 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -174,18 +174,19 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) { // This is quite complex // neeed to recurise down the nested buckets to build series - ElasticDatasource.prototype._processBuckets = function(buckets, target, series, level, parentName) { - var seriesName, value, metric, i, y, bucket, childBucket; + ElasticDatasource.prototype._processBuckets = function(aggs, target, series, level, parentName) { + var seriesName, value, metric, i, y, bucket, childBucket, aggDef, esAgg; + var buckets; + var dataFound = 0; - for (i = 0; i < buckets.length; i++) { - bucket = buckets[i]; - childBucket = bucket['b' + level]; + aggDef = target.bucketAggs[level]; + esAgg = aggs[aggDef.id]; - if (childBucket && childBucket.buckets) { - seriesName = parentName + ' ' + bucket.key; - this._processBuckets(childBucket.buckets, target, series, level+1, seriesName); - } else { + for (i = 0; i < esAgg.buckets.length; i++) { + bucket = esAgg.buckets[i]; + // if last agg collect series + if (level === target.bucketAggs.length - 1) { for (y = 0; y < target.metrics.length; y++) { metric = target.metrics[y]; seriesName = parentName; @@ -195,13 +196,16 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) { value = bucket.doc_count; } else { seriesName += ' ' + metric.field + ' ' + metric.type; - value = bucket['m' + y.toString()].value; + value = bucket[metric.id].value; } var serie = series[seriesName] = series[seriesName] || {target: seriesName, datapoints: []}; serie.datapoints.push([value, bucket.key]); } } + else { + this._processBuckets(bucket, target, series, level+1, parentName + ' ' + bucket.key); + } } }; @@ -214,11 +218,11 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) { throw { message: response.error }; } - var buckets = response.aggregations["b0"].buckets; + var aggregations = response.aggregations; var target = targets[i]; var querySeries = {}; - this._processBuckets(buckets, target, querySeries, 1, target.refId); + this._processBuckets(aggregations, target, querySeries, 0, target.refId); for (var prop in querySeries) { if (querySeries.hasOwnProperty(prop)) { diff --git a/public/app/plugins/datasource/elasticsearch/metricAgg.js b/public/app/plugins/datasource/elasticsearch/metricAgg.js index ffe6c47ba40..538b543b716 100644 --- a/public/app/plugins/datasource/elasticsearch/metricAgg.js +++ b/public/app/plugins/datasource/elasticsearch/metricAgg.js @@ -39,7 +39,12 @@ function (angular, _, $) { $scope.addMetricAgg = function() { var addIndex = metricAggs.length; - metricAggs.splice(addIndex, 0, {type: "count", field: "select field" }); + + var id = _.reduce($scope.target.bucketAggs.concat($scope.target.metrics), function(max, val) { + return parseInt(val.id) > max ? parseInt(val.id) : max; + }, 0); + + metricAggs.splice(addIndex, 0, {type: "count", field: "select field", id: (id+1).toString()}); }; $scope.removeMetricAgg = function() { diff --git a/public/app/plugins/datasource/elasticsearch/queryBuilder.js b/public/app/plugins/datasource/elasticsearch/queryBuilder.js index 2f336b3a698..d1fc9719a11 100644 --- a/public/app/plugins/datasource/elasticsearch/queryBuilder.js +++ b/public/app/plugins/datasource/elasticsearch/queryBuilder.js @@ -54,13 +54,19 @@ function (angular) { break; } case 'terms': { - esAgg["terms"] = { "field": aggDef.field }; + esAgg.terms = { "field": aggDef.field }; + var size = parseInt(aggDef.size, 10); + if (size > 0) { esAgg.terms.size = size; } + if (aggDef.orderBy) { + esAgg.terms.order = {}; + esAgg.terms.order[aggDef.orderBy] = aggDef.order; + } break; } } nestedAggs.aggs = {}; - nestedAggs.aggs['b' + i] = esAgg; + nestedAggs.aggs[aggDef.id] = esAgg; nestedAggs = esAgg; } @@ -74,7 +80,7 @@ function (angular) { var aggField = {}; aggField[metric.type] = {field: metric.field}; - nestedAggs.aggs['m' + i] = aggField; + nestedAggs.aggs[metric.id] = aggField; } return query; diff --git a/public/app/plugins/datasource/elasticsearch/queryCtrl.js b/public/app/plugins/datasource/elasticsearch/queryCtrl.js index 2885f073b50..6cb4b6f3de9 100644 --- a/public/app/plugins/datasource/elasticsearch/queryCtrl.js +++ b/public/app/plugins/datasource/elasticsearch/queryCtrl.js @@ -15,16 +15,18 @@ function (angular, _, ElasticQueryBuilder) { if (!target) { return; } target.timeField = target.timeField || '@timestamp'; - target.metrics = target.metrics || [{ type: 'count' }]; + target.metrics = target.metrics || [{ type: 'count', id: '1' }]; target.bucketAggs = target.bucketAggs || []; target.bucketAggs = [ { type: 'terms', - field: '@hostname' + field: '@hostname', + id: '2' }, { type: 'date_histogram', - field: '@timestamp' + field: '@timestamp', + id: '3' }, ]; diff --git a/public/test/specs/elasticsearch-querybuilder-specs.js b/public/test/specs/elasticsearch-querybuilder-specs.js index 58dd269d482..e589302f3f4 100644 --- a/public/test/specs/elasticsearch-querybuilder-specs.js +++ b/public/test/specs/elasticsearch-querybuilder-specs.js @@ -9,29 +9,29 @@ define([ var builder = new ElasticQueryBuilder(); var query = builder.build({ - metrics: [{type: 'Count'}], + metrics: [{type: 'Count', id: '0'}], timeField: '@timestamp', - bucketAggs: [{type: 'date_histogram', field: '@timestamp'}], + bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '1'}], }); expect(query.query.filtered.filter.bool.must[0].range["@timestamp"].gte).to.be("$timeFrom"); - expect(query.aggs["b0"].date_histogram.extended_bounds.min).to.be("$timeFrom"); + expect(query.aggs["1"].date_histogram.extended_bounds.min).to.be("$timeFrom"); }); it('with multiple bucket aggs', function() { var builder = new ElasticQueryBuilder(); var query = builder.build({ - metrics: [{type: 'Count'}], + metrics: [{type: 'count', id: '1'}], timeField: '@timestamp', bucketAggs: [ - {type: 'terms', field: '@host'}, - {type: 'date_histogram', field: '@timestamp'} + {type: 'terms', field: '@host', id: '2'}, + {type: 'date_histogram', field: '@timestamp', id: '3'} ], }); - expect(query.aggs["b0"].terms.field).to.be("@host"); - expect(query.aggs["b0"].aggs["b1"].date_histogram.field).to.be("@timestamp"); + expect(query.aggs["2"].terms.field).to.be("@host"); + expect(query.aggs["2"].aggs["3"].date_histogram.field).to.be("@timestamp"); }); @@ -39,14 +39,31 @@ define([ var builder = new ElasticQueryBuilder(); var query = builder.build({ - metrics: [{type: 'avg', field: '@value'}], - bucketAggs: [{type: 'date_histogram', field: '@timestamp'}], + metrics: [{type: 'avg', field: '@value', id: '1'}], + bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '2'}], }, 100, 1000); - var aggs = query.aggs["b0"].aggs; - expect(aggs["m0"].avg.field).to.be("@value"); + var aggs = query.aggs["2"].aggs; + expect(aggs["1"].avg.field).to.be("@value"); }); + it('with term agg and order by metric agg', function() { + var builder = new ElasticQueryBuilder(); + + var query = builder.build({ + metrics: [{type: 'avg', field: '@value', id: '1'}], + bucketAggs: [ + {type: 'term', size: 5, order: 'asc', orderBy: 'm0', id: '2' }, + {type: 'date_histogram', field: '@timestamp', id: '3'} + ], + }, 100, 1000); + + var firstLevel = query.aggs["2"]; + var secondLevel = firstLevel.aggs["3"]; + + // expect(firstLevel.aggs["m0"].avg.field).to.be("@value"); + expect(secondLevel.aggs["1"].avg.field).to.be("@value"); + }); }); diff --git a/public/test/specs/elasticsearch-queryctrl-specs.js b/public/test/specs/elasticsearch-queryctrl-specs.js index f8775529335..dc17c364f5d 100644 --- a/public/test/specs/elasticsearch-queryctrl-specs.js +++ b/public/test/specs/elasticsearch-queryctrl-specs.js @@ -26,27 +26,6 @@ define([ ctx.scope.init(); }); - it('should init selectSegments', function() { - expect(ctx.scope.selectSegments.length).to.be(2); - }); - - describe('initSelectSegments with 2 selects', function() { - - it('init selectSegments', function() { - ctx.scope.target.metrics = [ - {agg: 'count'}, - {agg: 'avg', field: 'value'}, - ]; - ctx.scope.initSelectSegments(); - - expect(ctx.scope.selectSegments.length).to.be(5); - expect(ctx.scope.selectSegments[0].value).to.be('count'); - expect(ctx.scope.selectSegments[1].value).to.be(' and '); - expect(ctx.scope.selectSegments[2].value).to.be('avg'); - expect(ctx.scope.selectSegments[3].value).to.be('value'); - }); - }); - }); }); diff --git a/public/test/specs/elasticsearch-specs.js b/public/test/specs/elasticsearch-specs.js index 84e25a67814..f4de2cf3e8c 100644 --- a/public/test/specs/elasticsearch-specs.js +++ b/public/test/specs/elasticsearch-specs.js @@ -23,12 +23,12 @@ define([ beforeEach(function() { result = ctx.ds._processTimeSeries([{ refId: 'A', - metrics: [{agg: 'count'}], - bucketAggs: [{type: 'date_histogram', field: '@timestamp'}], + metrics: [{type: 'count', id: '1'}], + bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '2'}], }], { responses: [{ aggregations: { - "b0": { + "2": { buckets: [ { doc_count: 10, @@ -60,20 +60,20 @@ define([ beforeEach(function() { result = ctx.ds._processTimeSeries([{ refId: 'A', - metrics: [{agg: 'count'}, {agg: 'avg', field: 'value'}], - bucketAggs: [{type: 'date_histogram', field: '@timestamp'}], + metrics: [{type: 'count', id: '1'}, {type: 'avg', field: 'value', id: '2'}], + bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '3'}], }], { responses: [{ aggregations: { - "b0": { + "3": { buckets: [ { - "m1": {value: 88}, + "2": {value: 88}, doc_count: 10, key: 1000 }, { - "m1": {value: 99}, + "2": {value: 99}, doc_count: 15, key: 2000 } @@ -103,15 +103,15 @@ define([ beforeEach(function() { result = ctx.ds._processTimeSeries([{ refId: 'A', - metrics: [{agg: 'count'}], - bucketAggs: [{type: 'terms', field: 'host'}, {type: 'date_histogram', field: '@timestamp'}], + metrics: [{type: 'count', id: '1'}], + bucketAggs: [{type: 'terms', field: 'host', id: '2'}, {type: 'date_histogram', field: '@timestamp', id: '3'}], }], { responses: [{ aggregations: { - "b0": { + "2": { buckets: [ { - "b1": { + "3": { buckets: [ {doc_count: 1, key: 1000}, {doc_count: 3, key: 2000} @@ -121,7 +121,7 @@ define([ key: 'server1', }, { - "b1": { + "3": { buckets: [ {doc_count: 2, key: 1000}, {doc_count: 8, key: 2000}