Use MongoDB to calculate the number of sessions per badges + Simplified count of fields
MODIFY
src/server/rest/service/UserService.ts
src/server/rest/service/UserService.ts
@@ -238,7 +238,7 @@ export default class UserService {
{ verificationToken: null, verifiedAt: null });
for (const tag of user.tags) {
- if (tag.sessionCount > 0) {
+ if (tag.transactionsCount > 0) {
tag.active = false;
tag.lastChangedOn = new Date();
tag.lastChangedBy = { id: req.user.id };
@@ -433,7 +433,7 @@ export default class UserService {
const foundTag = filteredRequest.tags.find((tag) => tag.id === previousTag.id);
if (!foundTag) {
// Tag not found in the current tag list, will be deleted or deactivated.
- if (previousTag.sessionCount > 0) {
+ if (previousTag.transactionsCount > 0) {
if (previousTag.active) {
previousTag.active = false;
previousTag.lastChangedOn = lastChangedOn;

MODIFY
src/storage/mongodb/DatabaseUtils.ts
src/storage/mongodb/DatabaseUtils.ts
@@ -168,19 +168,17 @@ export default class DatabaseUtils {
if (!lookupParams.pipelineMatch) {
lookupParams.pipelineMatch = {};
}
- lookupParams.pipelineMatch['$expr'] = lookupParams.localField.includes('.') && !lookupParams.oneToOneCardinality ?
- { '$in': [`$${lookupParams.foreignField}`, '$$fieldVar.' + lookupParams.localField.split('.')[1]] } :
- { '$eq': [`$${lookupParams.foreignField}`, '$$fieldVar'] };
+ lookupParams.pipelineMatch['$expr'] = { '$eq': [`$${lookupParams.foreignField}`, '$$fieldVar'] };
const pipeline: any[] = [
{ '$match': lookupParams.pipelineMatch }
];
if (!Utils.isEmptyArray(additionalPipeline)) {
pipeline.push(...additionalPipeline);
}
- if (lookupParams.countField) {
+ if (lookupParams.count) {
pipeline.push({
'$group': {
- '_id': `$${lookupParams.countField}`,
+ '_id': `$${lookupParams.asField}`,
'count': { '$sum': 1 }
}
});
@@ -199,9 +197,7 @@ export default class DatabaseUtils {
lookupParams.aggregation.push({
$lookup: {
from: DatabaseUtils.getCollectionName(lookupParams.tenantID, collection),
- 'let': { 'fieldVar': `$${lookupParams.localField.includes('.') && !lookupParams.oneToOneCardinality ?
- lookupParams.localField.split('.')[0] :
- lookupParams.localField}` },
+ 'let': { 'fieldVar': `$${lookupParams.localField}` },
pipeline,
'as': lookupParams.asField
}
@@ -228,6 +224,20 @@ export default class DatabaseUtils {
}
}`));
}
+ // Set only the count
+ if (lookupParams.count) {
+ lookupParams.aggregation.push({
+ $unwind: {
+ path: `$${lookupParams.asField}`,
+ preserveNullAndEmptyArrays: true
+ }
+ });
+ lookupParams.aggregation.push(JSON.parse(`{
+ "$addFields": {
+ "${lookupParams.asField}": "$${lookupParams.asField}.count"
+ }
+ }`));
+ }
}
public static pushChargingStationInactiveFlag(aggregation: any[]): void {

MODIFY
src/storage/mongodb/MongoDBStorage.ts
src/storage/mongodb/MongoDBStorage.ts
@@ -115,6 +115,7 @@ export default class MongoDBStorage {
await this.handleIndexesInCollection(collections, tenantID, 'transactions', [
{ fields: { timestamp: 1 } },
{ fields: { chargeBoxID: 1 } },
+ { fields: { tagID: 1 } },
{ fields: { userID: 1 } }
]);
// Invoices

MODIFY
src/storage/mongodb/UserStorage.ts
src/storage/mongodb/UserStorage.ts
@@ -563,11 +563,6 @@ export default class UserStorage {
DatabaseUtils.pushTagLookupInAggregation({
tenantID, aggregation, localField: '_id', foreignField: 'userID', asField: 'tags'
});
- if (dbParams === Constants.DB_PARAMS_SINGLE_RECORD) {
- DatabaseUtils.pushTransactionsLookupInAggregation({
- tenantID, aggregation, localField: '_id', foreignField: 'userID', asField: 'sessionsCount', countField: 'tagID'
- });
- }
// Select non-synchronized billing data
if (params.notSynchronizedBillingData) {
filters.$or = [
@@ -583,11 +578,9 @@ export default class UserStorage {
$match: filters
});
}
- // Add post filter
+ // Add additional filters
if (params.notAssignedToCarID) {
- const notAssignedToCarIDFilter = {
- '$or': []
- };
+ const notAssignedToCarIDFilter = { '$or': [] };
DatabaseUtils.pushUserCarLookupInAggregation({
tenantID, aggregation, localField: '_id', foreignField: 'userID', asField: 'carUsers'
});
@@ -602,26 +595,19 @@ export default class UserStorage {
Utils.convertToObjectID(includeCarUserID)) };
notAssignedToCarIDFilter.$or.push(includeCarUserIDsFilter);
}
- // Filters
- if (filters) {
+ // Add
aggregation.push({
$match: notAssignedToCarIDFilter
});
}
- }
// Add Site
if (params.siteIDs || params.excludeSiteID) {
DatabaseUtils.pushSiteUserLookupInAggregation({
- tenantID, aggregation, localField: '_id', foreignField: 'userID',
- asField: 'siteusers'
+ tenantID, aggregation, localField: '_id', foreignField: 'userID', asField: 'siteusers'
});
if (params.siteIDs) {
aggregation.push({
- $match: {
- 'siteusers.siteID': {
- $in: params.siteIDs.map((site) => Utils.convertToObjectID(site))
- }
- }
+ $match: { 'siteusers.siteID': { $in: params.siteIDs.map((site) => Utils.convertToObjectID(site)) } }
});
} else if (params.excludeSiteID) {
aggregation.push({
@@ -665,6 +651,15 @@ export default class UserStorage {
aggregation.push({
$limit: limit
});
+ // Add Number of Session per Badge
+ if (dbParams === Constants.DB_PARAMS_SINGLE_RECORD) {
+ // Transactions per Tag
+ DatabaseUtils.pushArrayLookupInAggregation('tags', DatabaseUtils.pushTransactionsLookupInAggregation.bind(this), {
+ tenantID, aggregation: aggregation, localField: 'tags.id', foreignField: 'tagID',
+ count: true, asField: 'tags.transactionsCount', oneToOneCardinality: false,
+ objectIDFields: ['createdBy', 'lastChangedBy']
+ });
+ }
// Add Created By / Last Changed By
DatabaseUtils.pushCreatedLastChangedInAggregation(tenantID, aggregation);
// Project
@@ -676,19 +671,6 @@ export default class UserStorage {
allowDiskUse: true
})
.toArray();
- // Clean user object
- for (const userMDB of usersMDB) {
- delete (userMDB as any).siteusers;
- if ((userMDB as any).sessionsCount) {
- for (const sessionCount of (userMDB as any).sessionsCount) {
- const tag = userMDB.tags.find((value) => value.id === sessionCount.id);
- if (tag) {
- tag.sessionCount = sessionCount.count;
- }
- }
- delete (userMDB as any).sessionsCount;
- }
- }
// Debug
Logging.traceEnd(MODULE_NAME, 'getUsers', uniqueTimerID, { params });
// Ok

MODIFY
src/types/Tag.ts
src/types/Tag.ts
@@ -9,6 +9,6 @@ export default interface Tag {
userID?: string;
lastChangedBy?: Partial<User>;
lastChangedOn?: Date;
- sessionCount?: number;
+ transactionsCount?: number;
ocpiToken?: OCPIToken;
}

MODIFY
src/types/database/DbLookup.ts
src/types/database/DbLookup.ts
@@ -7,7 +7,7 @@ export default interface DbLookup {
asField: string;
objectIDFields?: string[];
projectedFields?: string[];
- countField?: string;
+ count?: boolean;
oneToOneCardinality?: boolean;
oneToOneCardinalityNotNull?: boolean;
pipelineMatch?: any;

Use MongoDB to calculate the number of sessions per badges + Simplified count of fields