Final changes for backend before merging main branch
MODIFY
src/server/rest/v1/service/SiteAreaService.ts
src/server/rest/v1/service/SiteAreaService.ts
@@ -261,7 +261,7 @@ export default class SiteAreaService {
siteAreaID: filteredRequest.SiteAreaID,
startDate: filteredRequest.StartDate,
endDate: filteredRequest.EndDate,
- });
+ }, ['startedAt', 'instantAmps', 'instantWatts', 'limitAmps', 'limitWatts']);
siteArea.values = siteAreaDetailedData;
// Return
res.json(siteArea);

MODIFY
src/storage/mongodb/ConsumptionStorage.ts
src/storage/mongodb/ConsumptionStorage.ts
-import global, { FilterParams } from '../../types/GlobalType';
+import global, { FilterParams, GroupParams } from '../../types/GlobalType';
import Constants from '../../utils/Constants';
import Consumption from '../../types/Consumption';
@@ -190,31 +190,6 @@ export default class ConsumptionStorage {
const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getSiteAreaConsumptions');
// Check
await DatabaseUtils.checkTenant(tenantID);
- const facets = {};
- // Specific filters for each type of data
- const filterTypes = [
- {
- name: 'assetConsumptions',
- filters: { instantWatts : { '$gte': 0 }, assetID : { '$ne': null } },
- projectFields: [ 'startedAt', 'instantAmps', 'instantWatts' ]
- },
- // {
- // name: 'assetProductions',
- // filters: { instantWatts : { '$lt': 0 }, assetID : { '$ne': null } },
- // projectFields: [ 'startedAt', 'instantAmps', 'instantWatts' ]
- // },
- // {
- // name: 'chargingStationConsumptions',
- // filters: { chargeBoxID : { '$ne': null } },
- // projectFields: [ 'startedAt', 'instantAmps', 'instantWatts' ]
- // },
- // {
- // name: 'netConsumptions',
- // filters: {},
- // projectFields: ['startedAt', 'instantAmps', 'instantWatts', 'limitAmps', 'limitWatts']
- // }
- ];
- for (const filterValue of filterTypes) {
// Create filters
const filters: FilterParams = {};
// ID
@@ -233,8 +208,6 @@ export default class ConsumptionStorage {
if (params.endDate) {
filters.startedAt.$lte = Utils.convertToDate(params.endDate);
}
- // Type of query
- Object.assign(filters, filterValue.filters);
// Create Aggregation
const aggregation = [];
// Filters
@@ -243,24 +216,58 @@ export default class ConsumptionStorage {
$match: filters
});
}
- // Group consumption values per minute
- aggregation.push({
- $group: {
+ const facets = {};
+ // Specific filters for each type of data
+ const detailedGroups = ['assetConsumptions', 'assetProductions', 'chargingStationConsumptions', 'netConsumptions'];
+ // Subset project fields
+ const projectFieldsNonNet = [...projectFields];
+ projectFieldsNonNet.splice(projectFieldsNonNet.indexOf('limitWatts'), 1);
+ projectFieldsNonNet.splice(projectFieldsNonNet.indexOf('limitAmps'), 1);
+ for (const detailedType of detailedGroups) {
+ // Create filters
+ const facetFilters: FilterParams = {};
+ // Type of query
+ if (detailedType === 'assetConsumptions') {
+ facetFilters.instantWatts = { '$gte': 0 };
+ facetFilters.assetID = { '$ne': null };
+ } else if (detailedType === 'assetProductions') {
+ facetFilters.instantWatts = { '$lt': 0 };
+ facetFilters.assetID = { '$ne': null };
+ } else if (detailedType === 'chargingStationConsumptions') {
+ facetFilters.chargeBoxID = { '$ne': null };
+ }
+ // Create Aggregation
+ const facetAggregation = [];
+ // Filters
+ if (facetFilters) {
+ facetAggregation.push({
+ $match: facetFilters
+ });
+ }
+ // grouping fields
+ const groupFields : GroupParams = {
_id: {
year: { '$year': '$startedAt' },
month: { '$month': '$startedAt' },
day: { '$dayOfMonth': '$startedAt' },
hour: { '$hour': '$startedAt' },
minute: { '$minute': '$startedAt' }
- },
- instantWatts: { $sum: '$instantWatts' },
- instantAmps: { $sum: '$instantAmps' },
- limitWatts: { $last: '$limitSiteAreaWatts' },
- limitAmps: { $last: '$limitSiteAreaAmps' }
}
+ };
+ groupFields.instantWatts = { $sum: { '$abs': '$instantWatts' } };
+ groupFields.instantAmps = { $sum: { '$abs': '$instantAmps' } };
+ if (detailedType === 'netConsumptions') {
+ groupFields.limitWatts = { $last: '$limitSiteAreaWatts' };
+ }
+ if (detailedType === 'netConsumptions') {
+ groupFields.limitAmps = { $last: '$limitSiteAreaAmps' };
+ }
+ // Group consumption values per minute
+ facetAggregation.push({
+ $group: groupFields
});
// Rebuild the date
- aggregation.push({
+ facetAggregation.push({
$addFields: {
startedAt: {
$dateFromParts: { 'year': '$_id.year', 'month': '$_id.month', 'day': '$_id.day', 'hour': '$_id.hour', 'minute': '$_id.minute' }
@@ -268,29 +275,36 @@ export default class ConsumptionStorage {
}
});
// Same date
- aggregation.push({
+ facetAggregation.push({
$addFields: {
endedAt: '$startedAt'
}
});
// Convert Object ID to string
- DatabaseUtils.pushConvertObjectIDToString(aggregation, 'siteID');
- DatabaseUtils.pushConvertObjectIDToString(aggregation, 'siteAreaID');
- DatabaseUtils.pushConvertObjectIDToString(aggregation, 'userID');
- aggregation.push({
+ DatabaseUtils.pushConvertObjectIDToString(facetAggregation, 'siteID');
+ DatabaseUtils.pushConvertObjectIDToString(facetAggregation, 'siteAreaID');
+ DatabaseUtils.pushConvertObjectIDToString(facetAggregation, 'userID');
+ facetAggregation.push({
$sort: {
startedAt: 1
}
});
// Project
- DatabaseUtils.projectFields(aggregation, filterValue.projectFields, ['_id']);
+ if (detailedType === 'netConsumptions') {
+ DatabaseUtils.projectFields(facetAggregation, projectFields, ['_id']);
+ } else {
+ DatabaseUtils.projectFields(facetAggregation, projectFieldsNonNet, ['_id']);
+ }
// Add projection as field in facet
- facets[filterValue.name] = aggregation;
+ facets[detailedType] = facetAggregation;
}
+ // push the facet based aggregation pipelines
+ aggregation.push({ $facet: facets });
+
// Read DB
const consumptionsMDB = await global.database.getCollection<Consumption>(tenantID, 'consumptions')
- .aggregate([{ $facet: facets }], { allowDiskUse: true })
+ .aggregate(aggregation, { allowDiskUse: true })
.toArray();
const siteAreaData: SiteAreaValues = {

MODIFY
src/types/GlobalType.ts
src/types/GlobalType.ts
@@ -25,6 +25,10 @@ export interface FilterParams {
[param: string]: any | string[];
}
+export interface GroupParams {
+ [param: string]: any;
+}
+
export interface ActionsResponse {
inSuccess: number;
inError: number;

Final changes for backend before merging main branch