diff --git a/lib/cartodb/models/aggregation/aggregation-query.js b/lib/cartodb/models/aggregation/aggregation-query.js index d09a9665..fd860318 100644 --- a/lib/cartodb/models/aggregation/aggregation-query.js +++ b/lib/cartodb/models/aggregation/aggregation-query.js @@ -118,7 +118,8 @@ const gridResolution = ctx => `(${256*0.00028/ctx.res}*!scale_denominator!)::dou const aggregationQueryTemplates = { 'centroid': ctx => ` - WITH _cdb_params AS ( + WITH + _cdb_params AS ( SELECT ${gridResolution(ctx)} AS res, !bbox! AS bbox @@ -142,34 +143,66 @@ const aggregationQueryTemplates = { `, 'point-grid': ctx => ` - WITH _cdb_params AS ( - SELECT - ${gridResolution(ctx)} AS res, - !bbox! AS bbox - ), - _cdb_clusters AS ( - 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 - ${dimensionDefs(ctx)} - ${aggregateColumnDefs(ctx)} - FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params - WHERE the_geom_webmercator && _cdb_params.bbox - GROUP BY _cdb_gx, _cdb_gy ${dimensionNames(ctx)} - ) - SELECT - ST_SetSRID(ST_MakePoint((_cdb_gx+0.5)*res, (_cdb_gy+0.5)*res), 3857) AS the_geom_webmercator - ${dimensionNames(ctx)} - ${aggregateColumnNames(ctx)} - FROM _cdb_clusters, _cdb_params - `, - - 'point-sample': ctx => ` - WITH _cdb_params AS ( + WITH + _cdb_params AS ( SELECT ${gridResolution(ctx)} AS res, !bbox! AS bbox - ), _cdb_clusters AS ( + ), + _cdb_clusters AS ( + 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 + ${dimensionDefs(ctx)} + ${aggregateColumnDefs(ctx)} + FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params + WHERE the_geom_webmercator && _cdb_params.bbox + GROUP BY _cdb_gx, _cdb_gy ${dimensionNames(ctx)} + ) + SELECT + ST_SetSRID(ST_MakePoint((_cdb_gx+0.5)*res, (_cdb_gy+0.5)*res), 3857) AS the_geom_webmercator + ${dimensionNames(ctx)} + ${aggregateColumnNames(ctx)} + FROM _cdb_clusters, _cdb_params + `, + + 'point-sample': ctx => ` + WITH + _cdb_params AS ( + SELECT + ${gridResolution(ctx)} AS res, + !bbox! AS bbox + ), + _cdb_clusters AS ( + SELECT + MIN(cartodb_id) AS cartodb_id + ${dimensionDefs(ctx)} + ${aggregateColumnDefs(ctx)} + FROM (${ctx.sourceQuery}) _cdb_query, _cdb_params + WHERE _cdb_query.the_geom_webmercator && _cdb_params.bbox + GROUP BY + Floor(ST_X(_cdb_query.the_geom_webmercator)/_cdb_params.res), + Floor(ST_Y(_cdb_query.the_geom_webmercator)/_cdb_params.res) + ${dimensionNames(ctx)} + ) + SELECT + _cdb_clusters.cartodb_id, + the_geom, the_geom_webmercator + ${dimensionNames(ctx)} + ${aggregateColumnNames(ctx)} + FROM + _cdb_clusters INNER JOIN (${ctx.sourceQuery}) _cdb_query + ON (_cdb_clusters.cartodb_id = _cdb_query.cartodb_id) + `, + + 'full-sample': ctx => ` + WITH + _cdb_params AS ( + SELECT + ${gridResolution(ctx)} AS res, + !bbox! AS bbox + ), + _cdb_clusters AS ( SELECT MIN(cartodb_id) AS cartodb_id ${dimensionDefs(ctx)} @@ -181,9 +214,7 @@ const aggregationQueryTemplates = { Floor(ST_Y(_cdb_query.the_geom_webmercator)/_cdb_params.res) ${dimensionNames(ctx)} ) SELECT - _cdb_clusters.cartodb_id, - the_geom, the_geom_webmercator - ${dimensionNames(ctx)} + _cdb_query.* ${aggregateColumnNames(ctx)} FROM _cdb_clusters INNER JOIN (${ctx.sourceQuery}) _cdb_query diff --git a/test/acceptance/aggregation.js b/test/acceptance/aggregation.js index 12dffeee..14040592 100644 --- a/test/acceptance/aggregation.js +++ b/test/acceptance/aggregation.js @@ -732,6 +732,51 @@ describe('aggregation', function () { }); }); + it('aggregates with full-sample placement', function (done) { + this.mapConfig = createVectorMapConfig([ + { + type: 'cartodb', + options: { + sql: POINTS_SQL_1, + resolution: 256, + aggregation: { + placement: 'point-grid', + columns: { + total: { + aggregate_function: 'sum', + aggregated_column: 'value' + }, + v_avg: { + aggregate_function: 'avg', + aggregated_column: 'value' + } + }, + threshold: 1 + } + } + } + ]); + + this.testClient = new TestClient(this.mapConfig); + + this.testClient.getTile(0, 0, 0, { format: 'mvt' }, function (err, res, mvt) { + if (err) { + return done(err); + } + + const geojsonTile = JSON.parse(mvt.toGeoJSONSync(0)); + + assert.ok(Array.isArray(geojsonTile.features)); + assert.ok(geojsonTile.features.length > 0); + + const feature = geojsonTile.features[0]; + + assert.ok(feature.properties.hasOwnProperty('value'), 'Missing value property'); + + done(); + }); + }); + it('should fail with bad resolution', function (done) { this.mapConfig = createVectorMapConfig([ { @@ -802,10 +847,10 @@ describe('aggregation', function () { } assert.deepEqual(body, { - errors: [ 'Invalid placement. Valid values: centroid, point-grid, point-sample'], + errors: [ 'Invalid placement. Valid values: centroid, point-grid, point-sample, full-sample'], errors_with_context:[{ type: 'layer', - message: 'Invalid placement. Valid values: centroid, point-grid, point-sample', + message: 'Invalid placement. Valid values: centroid, point-grid, point-sample, full-sample', layer: { id: "layer0", index: 0,