diff --git a/lib/cartodb/models/aggregation/aggregation-query.js b/lib/cartodb/models/aggregation/aggregation-query.js index bf995c82..ca6d3431 100644 --- a/lib/cartodb/models/aggregation/aggregation-query.js +++ b/lib/cartodb/models/aggregation/aggregation-query.js @@ -46,20 +46,27 @@ const SUPPORTED_AGGREGATE_FUNCTIONS = { }, 'max': { sql: (column_name, params) => `max(${params.aggregated_column || column_name})` + }, + 'mode': { + sql: (column_name, params) => `cdb_mode(${params.aggregated_column || column_name})` } }; const aggregateColumns = ctx => { - // TODO: always add count - let columns = ctx.columns || {}; - if (Object.keys(columns).length === 0) { - // default aggregation - columns = { - _cdb_feature_count: { - aggregate_function: 'count' - } - }; - } + return Object.assign({ + _cdb_feature_count: { + aggregate_function: 'count' + } + }, ctx.columns || {}); +}; + +const aggregateColumnNames = ctx => { + let columns = aggregateColumns(ctx); + return Object.keys(columns).join(', '); +}; + +const aggregateColumnDefs = ctx => { + let columns = aggregateColumns(ctx); return Object.keys(columns).map(column_name => { const aggregate_function = columns[column_name].aggregate_function || 'count'; const aggregate_definition = SUPPORTED_AGGREGATE_FUNCTIONS[aggregate_function]; @@ -94,7 +101,7 @@ const aggregationQueryTemplates = { AVG(ST_Y(_cdb_query.the_geom_webmercator)) ), 3857 ) AS the_geom_webmercator, - ${aggregateColumns(ctx)} + ${aggregateColumnDefs(ctx)} FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params WHERE _cdb_query.the_geom_webmercator && _cdb_params.bbox GROUP BY @@ -112,14 +119,14 @@ const aggregationQueryTemplates = { SELECT Floor(ST_X(_cdb_query.the_geom_webmercator)/_cdb_params.res)::int AS _cdb_gx, Floor(ST_Y(_cdb_query.the_geom_webmercator)/_cdb_params.res)::int AS _cdb_gy, - ${aggregateColumns(ctx)} + ${aggregateColumnDefs(ctx)} FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params WHERE the_geom_webmercator && _cdb_params.bbox GROUP BY _cdb_gx, _cdb_gy ) SELECT ST_SetSRID(ST_MakePoint(_cdb_gx*(res+0.5), _cdb_gy*(res+0.5)), 3857) AS the_geom_webmercator, - _cdb_feature_count + ${aggregateColumnNames(ctx)} FROM _cdb_clusters, _cdb_params `, @@ -132,7 +139,7 @@ const aggregationQueryTemplates = { ), _cdb_clusters AS ( SELECT MIN(cartodb_id) AS cartodb_id, - ${aggregateColumns(ctx)} + ${aggregateColumnDefs(ctx)} FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params WHERE _cdb_query.the_geom_webmercator && _cdb_params.bbox GROUP BY @@ -141,7 +148,7 @@ const aggregationQueryTemplates = { ) SELECT _cdb_clusters.cartodb_id, the_geom, the_geom_webmercator, - _cdb_feature_count + ${aggregateColumnNames(ctx)} FROM _cdb_clusters INNER JOIN (${ctx.sourceQuery}) _cdb_query ON (_cdb_clusters.cartodb_id = _cdb_query.cartodb_id) diff --git a/test/acceptance/aggregation.js b/test/acceptance/aggregation.js index 46ea56b0..aa245fac 100644 --- a/test/acceptance/aggregation.js +++ b/test/acceptance/aggregation.js @@ -20,6 +20,7 @@ describe('aggregation', function () { const POINTS_SQL_1 = ` select + x + 4 as cartodb_id, st_setsrid(st_makepoint(x*10, x*10), 4326) as the_geom, st_transform(st_setsrid(st_makepoint(x*10, x*10), 4326), 3857) as the_geom_webmercator, x as value @@ -28,6 +29,7 @@ describe('aggregation', function () { const POINTS_SQL_TIMESTAMP_1 = ` select + row_number() over() AS cartodb_id, st_setsrid(st_makepoint(x*10, x*10), 4326) as the_geom, st_transform(st_setsrid(st_makepoint(x*10, x*10), 4326), 3857) as the_geom_webmercator, x as value, @@ -41,6 +43,7 @@ describe('aggregation', function () { const POINTS_SQL_2 = ` select + x + 4 as cartodb_id, st_setsrid(st_makepoint(x*10, x*10*(-1)), 4326) as the_geom, st_transform(st_setsrid(st_makepoint(x*10, x*10*(-1)), 4326), 3857) as the_geom_webmercator, x as value, @@ -50,6 +53,7 @@ describe('aggregation', function () { const POLYGONS_SQL_1 = ` select + x + 4 as cartodb_id, st_buffer(st_setsrid(st_makepoint(x*10, x*10), 4326)::geography, 100000)::geometry as the_geom, st_transform( st_buffer(st_setsrid(st_makepoint(x*10, x*10), 4326)::geography, 100000)::geometry,