Be able to aggregate by a field

This commit is contained in:
Daniel García Aubert
2019-03-01 11:21:18 +01:00
parent 92e62069d4
commit 77d5d8ebd4
4 changed files with 181 additions and 53 deletions
@@ -43,7 +43,7 @@ module.exports = class AggregatedFeaturesLayergroupController {
authorize(this.authBackend),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ATTRIBUTES),
cleanUpQueryParams(),
cleanUpQueryParams([ 'aggregation' ]),
createMapStoreMapConfigProvider(
this.mapStore,
this.userLimitsBackend,
@@ -67,11 +67,13 @@ function getClusteredFeatures (clusterBackend) {
const { user, token } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { layer, z: zoom, clusterId } = req.params;
const { aggregation } = req.query;
const params = {
user, token,
dbuser, dbname, dbpassword, dbhost, dbport,
layer, zoom, clusterId
layer, zoom, clusterId,
aggregation
};
clusterBackend.getClusterFeatures(mapConfigProvider, params, (err, features, stats = {}) => {
+24 -10
View File
@@ -38,6 +38,7 @@ module.exports = class ClusterBackend {
return callback(error);
}
const { aggregation } = params;
const query = layer.options.sql_raw;
const resolution = layer.options.aggregation.resolution || 1;
@@ -48,7 +49,7 @@ module.exports = class ClusterBackend {
const { zoom, clusterId } = params;
getClusterFeatures(pg, zoom, clusterId, columns, query, resolution, (err, features) => {
getClusterFeatures(pg, zoom, clusterId, columns, query, resolution, aggregation, (err, features) => {
if (err) {
return callback(err);
}
@@ -85,8 +86,8 @@ function getColumnsName (pg, query, callback) {
}, true);
}
function getClusterFeatures (pg, zoom, clusterId, columns, query, resolution, callback) {
const sql = clusterFeaturesQuery({
function getClusterFeatures (pg, zoom, clusterId, columns, query, resolution, aggregation, callback) {
let sql = clusterFeaturesQuery({
zoom: zoom,
id: clusterId,
query: query,
@@ -94,6 +95,17 @@ function getClusterFeatures (pg, zoom, clusterId, columns, query, resolution, ca
columns: columns
});
if (aggregation !== undefined) {
aggregation = JSON.parse(aggregation);
const { columns = [], expresions = [] } = aggregation;
sql = aggregationQuery({
columns,
query: sql,
expresions
});
}
debug('> getClusterFeatures:', sql);
pg.query(sql, (err, data) => {
@@ -133,15 +145,17 @@ const clusterFeaturesQuery = ctx => `
) __cdb_non_geoms_query
`;
// SQL expression to compute the aggregation resolution (grid cell size).
// This is defined by the ctx.res parameter, which is the number of grid cells per tile linear dimension
// (i.e. each tile is divided into ctx.res*ctx.res cells).
// We limit the the minimum resolution to avoid division by zero problems. The limit used is
// the pixel size of zoom level 30 (i.e. 1/2*(30+8) of the full earth web-mercator extent), which is about 0.15 mm.
// Computing this using !scale_denominator!, !pixel_width! or !pixel_height! produces
// inaccurate results due to rounding present in those values.
const gridResolution = ctx => {
const minimumResolution = 2*Math.PI*6378137/Math.pow(2,38);
const pixelSize = `CDB_XYZ_Resolution(${ctx.zoom})`;
return `GREATEST(${256/ctx.res}*${pixelSize}, ${minimumResolution})::double precision`;
};
const aggregationQuery = ctx => `
SELECT
count(1) as _cdb_feature_count
${ctx.columns.length ? `,${ctx.columns.join(', ')}` : ''}
${ctx.expresions.length ? `,${ctx.expresions.join(', ')}` : ''}
FROM (${ctx.query}) __cdb_aggregation
${ctx.columns.length ? `GROUP BY ${ctx.columns.join(', ')}` : ''}
`;