Skip to main content

LLD: Compute Audit Summary Script

1. Objective

Replace the 13 dummy documents in the audit-summaries collection with real, computed summaries derived from the transformer collection (~405K docs). The script will aggregate transformer data at every level of the location hierarchy (SECTION → SUB_DIVISION → DIVISION → CIRCLE → ZONE → MESCOM) for each month.


2. Field Derivation from Transformer Schema

Every field in an auditSummary document is derived from one or more fields in the transformer collection. This section maps each field to its source.

2.1 Identity & Location

AuditSummary FieldSource
levelNot from TC. Set by the script based on aggregation level (SECTION, SUB_DIVISION, DIVISION, CIRCLE, ZONE, MESCOM)
monthDirect carry-forward from transformer.month (the group key)
location.*$first of corresponding transformer.location.* fields within the group. Safe because all TCs in a section share the same parent hierarchy

2.2 Summary Counts

AuditSummary FieldDerivation
totalTCCountCOUNT(*) — total transformer docs in the group
auditedCountCOUNT WHERE transformer.auditStatus === "AUDITED"
failedCountCOUNT WHERE transformer.auditStatus === "AUDIT_FAILED"

How transformer.auditStatus was determined (by backfillAuditStatus.js):

  • lossPercentage != nullAUDITED
  • lossPercentage == nullAUDIT_FAILED

2.3 Loss Buckets

Only counts TCs where transformer.auditStatus === "AUDITED". Each TC falls into exactly one bucket.

AuditSummary FieldCondition on transformer.lossPercentage
lossBuckets.belowMinus5lossPercentage < -5
lossBuckets.minus5to0-5 <= lossPercentage < 0
lossBuckets.zeroTo50 <= lossPercentage < 5
lossBuckets.fiveTo105 <= lossPercentage < 10
lossBuckets.tenTo1510 <= lossPercentage < 15
lossBuckets.fifteenTo2015 <= lossPercentage < 20
lossBuckets.above20lossPercentage >= 20

lossPercentage formula:

lossPercentage = ((tcConsumption * meterConstant) - installationConsumption)
/ (tcConsumption * meterConstant) * 100

2.4 Failed Reasons

Only counts TCs where transformer.auditStatus === "AUDIT_FAILED". Categories are non-exclusive (a TC can match multiple).

AuditSummary FieldCondition on Transformer FieldsWhy this causes audit failure
failedReasons.noMeterConstantmeterConstant is null or 0Can't compute tcConsumption * meterConstantlossPercentage not derivable
failedReasons.withoutInstallationConsumptioninstallationConsumption is null or 0No installation consumption → loss formula incomplete
failedReasons.noTcConsumptionWithRemarkstcConsumption === null AND remark !== nullTC meter not providing readings, explained by a remark (METER_NOT_RECORDING, CT_BURNT_OUT, NO_DISPLAY, METER_NOT_PROVIDED)
failedReasons.noTcConsumptionNoRemarkstcConsumption === null AND remark === nullTC meter not providing readings with no explanation — most concerning

tcConsumption formula:

tcConsumption = reading.finalValue - reading.initialValue

If either reading.initialValue or reading.finalValue is null, tcConsumption stays null.

2.5 Metadata

AuditSummary FieldSource
lastAuditedOnSet to new Date() at script execution time — not derived from any TC field

2.6 Chain of Dependencies

reading.initialValue ─┐
├─→ tcConsumption ─────────┐
reading.finalValue ──┘ │
├─→ lossPercentage ─→ auditStatus
meterConstant ───────────────────────────────────┤ │
│ ├─→ AUDITED → lossBuckets
installationConsumption (sum of tagged │ └─→ AUDIT_FAILED → failedReasons
installations' consumption) ───────────────────┘

remark ──────────────────────────────────→ used to classify failedReasons
(withRemarks vs noRemarks)

3. Algorithm

Phase 1: Clear existing collection

Delete ALL documents from audit-summaries collection (auditSummaryModel.deleteMany({}))

This removes all 13 dummy documents regardless of month, ensuring a clean slate before inserting real data.

Phase 2: Resolve target months

Input: config.months (optional string array, e.g., ["2025-09", "2025-10"])
If not provided → query transformer.distinct("month") to get all available months

Phase 3: Compute SECTION-level summaries (from transformer collection)

For each target month, run a single MongoDB aggregation pipeline on the transformer collection:

Pipeline:
$match → { month: <targetMonth> }
$group → by { sectionCode: "$location.sectionCode" }
Carry forward (via $first):
- sectionName, subDivisionCode, subDivisionName,
divisionCode, divisionName, circleCode, circleName,
zoneCode, zoneName
Compute:
- totalTCCount: { $sum: 1 }
- auditedCount: count where auditStatus === "AUDITED"
- failedCount: count where auditStatus === "AUDIT_FAILED"
- 7 loss bucket counts (conditional on AUDITED + lossPercentage range)
- 4 failed reason counts (conditional on AUDIT_FAILED + field checks)

This produces ~202 section summaries per month.

Phase 4: Roll up higher levels (from computed SECTION docs)

For each higher level, aggregate the SECTION-level results (in application memory, not a DB aggregation — only ~808 docs):

For each level in [SUB_DIVISION, DIVISION, CIRCLE, ZONE, MESCOM]:
Group SECTION docs by { month, <levelCode> }
Sum: totalTCCount, auditedCount, failedCount, all lossBuckets, all failedReasons
Carry forward: location names from the first section in the group
Set: level, lastAuditedOn = now

Grouping keys per level:

LevelGroup by
SUB_DIVISIONmonth + subDivisionCode
DIVISIONmonth + divisionCode
CIRCLEmonth + circleCode
ZONEmonth + zoneCode
MESCOMmonth only

Location fields populated per level:

LevelLocation fields set
SECTIONsectionCode/Name, subDivisionCode/Name, divisionCode/Name, circleCode/Name, zoneCode/Name
SUB_DIVISIONsubDivisionCode/Name, divisionCode/Name, circleCode/Name, zoneCode/Name
DIVISIONdivisionCode/Name, circleCode/Name, zoneCode/Name
CIRCLEcircleCode/Name, zoneCode/Name
ZONEzoneCode/Name
MESCOM(empty object)

Phase 5: Persist to database

Insert all computed docs (SECTION + all rolled-up levels) via insertMany

Collection is already cleared in Phase 1, so this is a straightforward bulk insert.

  • ordered: false for better performance (continues on individual failures)
  • Script is idempotent — Phase 1 clears everything, so re-running produces the same result

4. Script Design

File location

script/src/entities/auditSummary/computeAuditSummary.js

Invocation

Config name: auditSummary_computeAuditSummary

In config.json:

{
"scriptRunArray": ["auditSummary_computeAuditSummary"],
"input": {
"auditSummary": {
"computeAuditSummary": {
"months": ["2025-09", "2025-10", "2025-11", "2025-12"]
}
}
}
}

If months is omitted, the script auto-discovers all distinct months from the transformer collection.

Exports

export const tags = [];

export async function mainFunction(input) { ... }

Internal structure

mainFunction(input)
├── clearCollection() // Phase 1: delete all existing docs
├── resolveMonths(input.months) // Phase 2: get target months
├── for each month:
│ ├── computeSectionSummaries(month) // Phase 3: MongoDB aggregation
│ ├── rollUpToHigherLevels(sections) // Phase 4: in-memory grouping
│ └── collect all docs for this month
└── insertAllDocs(allDocs) // Phase 5: bulk insert

Key functions

computeSectionSummaries(month)SectionDoc[]

Runs the MongoDB aggregation pipeline (Phase 2) and returns an array of section-level summary objects ready for insertion.

rollUpToHigherLevels(sectionDocs)RolledUpDoc[]

Takes section docs for a single month, groups them by each higher level's code, sums all numeric fields, and returns SUB_DIVISION + DIVISION + CIRCLE + ZONE + MESCOM docs.

groupAndSum(docs, level, groupKeyFn, locationFn)Doc[]

Generic helper that groups an array of docs by a key, sums the numeric summary fields, and constructs the output doc with the correct level and location.


5. MongoDB Aggregation Pipeline (Phase 2 — detail)

[
{ $match: { month } },
{
$group: {
_id: "$location.sectionCode",

// Location (carry forward)
sectionName: { $first: "$location.sectionName" },
subDivisionCode: { $first: "$location.subDivisionCode" },
subDivisionName: { $first: "$location.subDivisionName" },
divisionCode: { $first: "$location.divisionCode" },
divisionName: { $first: "$location.divisionName" },
circleCode: { $first: "$location.circleCode" },
circleName: { $first: "$location.circleName" },
zoneCode: { $first: "$location.zoneCode" },
zoneName: { $first: "$location.zoneName" },

// Counts
totalTCCount: { $sum: 1 },
auditedCount: {
$sum: { $cond: [{ $eq: ["$auditStatus", "AUDITED"] }, 1, 0] }
},
failedCount: {
$sum: { $cond: [{ $eq: ["$auditStatus", "AUDIT_FAILED"] }, 1, 0] }
},

// Loss buckets (AUDITED only)
belowMinus5: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $lt: ["$lossPercentage", -5] }
]}, 1, 0
]}
},
minus5to0: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", -5] },
{ $lt: ["$lossPercentage", 0] }
]}, 1, 0
]}
},
zeroTo5: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", 0] },
{ $lt: ["$lossPercentage", 5] }
]}, 1, 0
]}
},
fiveTo10: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", 5] },
{ $lt: ["$lossPercentage", 10] }
]}, 1, 0
]}
},
tenTo15: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", 10] },
{ $lt: ["$lossPercentage", 15] }
]}, 1, 0
]}
},
fifteenTo20: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", 15] },
{ $lt: ["$lossPercentage", 20] }
]}, 1, 0
]}
},
above20: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDITED"] },
{ $gte: ["$lossPercentage", 20] }
]}, 1, 0
]}
},

// Failed reasons (AUDIT_FAILED only, non-exclusive)
noMeterConstant: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDIT_FAILED"] },
{ $in: ["$meterConstant", [null, 0]] }
]}, 1, 0
]}
},
withoutInstallationConsumption: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDIT_FAILED"] },
{ $in: ["$installationConsumption", [null, 0]] }
]}, 1, 0
]}
},
noTcConsumptionWithRemarks: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDIT_FAILED"] },
{ $eq: ["$tcConsumption", null] },
{ $ne: ["$remark", null] }
]}, 1, 0
]}
},
noTcConsumptionNoRemarks: {
$sum: { $cond: [
{ $and: [
{ $eq: ["$auditStatus", "AUDIT_FAILED"] },
{ $eq: ["$tcConsumption", null] },
{ $eq: ["$remark", null] }
]}, 1, 0
]}
},
}
}
]

6. In-Memory Roll-Up (Phase 3 — detail)

After SECTION docs are computed for a month, roll-up is done in-memory (not another DB query). With ~202 section docs per month, this is trivial.

Summable fields (summed during roll-up):
totalTCCount, auditedCount, failedCount,
lossBuckets.{ belowMinus5, minus5to0, zeroTo5, fiveTo10, tenTo15, fifteenTo20, above20 },
failedReasons.{ noMeterConstant, withoutInstallationConsumption,
noTcConsumptionWithRemarks, noTcConsumptionNoRemarks }

Roll-up example: SECTION → SUB_DIVISION

Input: 202 section docs for month "2025-09"
Group by: subDivisionCode
Output: 64 sub-division docs

For each group:
- level: "SUB_DIVISION"
- month: "2025-09"
- location: {
subDivisionCode, subDivisionName, ← from first section in group
divisionCode, divisionName,
circleCode, circleName,
zoneCode, zoneName
}
- totalTCCount: sum of sections' totalTCCount
- auditedCount: sum of sections' auditedCount
- ... (all summable fields)
- lastAuditedOn: new Date()

Same pattern repeats for DIVISION (group sections by divisionCode), CIRCLE (by circleCode), ZONE (by zoneCode), MESCOM (all sections in one group).


7. Persistence Strategy

// Phase 1: Clear entire collection
await auditSummaryModel.deleteMany({});

// Phase 5: Bulk insert all computed docs
await auditSummaryModel.insertMany(allDocs, { ordered: false });
  • Phase 1 clears the entire collection upfront (not filtered by month) — removes all dummy data
  • ordered: false for better insert performance (continues on individual failures)
  • Script is idempotent — safe to re-run

8. Validation & Logging

After computation, log these sanity checks per month:

CheckValidation
auditedCount + failedCount === totalTCCountPer section and per MESCOM
Sum of loss buckets === auditedCountPer section
MESCOM totalTCCount matches transformer.countDocuments({ month })Cross-collection
Total docs inserted per levelExpected counts match hierarchy

Log format:

[2025-09] SECTION: 202 docs | SUB_DIVISION: 64 | DIVISION: 14 | CIRCLE: 4 | ZONE: 2 | MESCOM: 1
[2025-09] MESCOM summary → total: 100392 | audited: 5512 | failed: 94880
[2025-09] ✓ auditedCount + failedCount === totalTCCount
[2025-09] ✓ lossBucket sum === auditedCount

9. Performance Estimate

OperationData sizeExpected time
Section aggregation (per month)~100K transformer docs~2–5 seconds (indexed on month)
In-memory roll-up (per month)~202 section docs<10 ms
Delete old docs~13 docs (current dummy)<100 ms
Insert new docs~1,148 docs total<1 second
Total (4 months)~10–25 seconds

10. Dependencies

DependencyImport path
transformerModel../../../../common/src/schemas/transformer.model.js
auditSummaryModel../../../../common/src/schemas/auditSummary.model.js
log../../utils/logger.js
assignDefaults../../utils/functions.js

No new dependencies required.


11. Error Handling

ScenarioHandling
No transformer docs for a monthLog warning, skip that month
Aggregation returns 0 sectionsLog error, skip insertion for that month
insertMany partial failureordered: false ensures other docs still insert; log failures
Script re-runIdempotent — deletes old data first

12. Testing Strategy

After running the script, execute the following tests in order. Each test is a standalone mongosh query with its expected outcome. All tests must pass.

Connection:

mongosh "<MONGO_CONNECTION_STRING>" --db dtcea-mumbai-demo --quiet

Test 1: Document count per level

Verify the correct number of docs were created at each level.

db.getCollection("audit-summaries").aggregate([
{ $group: { _id: "$level", count: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]).forEach(r => print(r._id, ":", r.count));

Expected output:

CIRCLE : 16 (4 circles × 4 months)
DIVISION : 56 (14 divisions × 4 months)
MESCOM : 4 (1 × 4 months)
SECTION : 808 (202 sections × 4 months)
SUB_DIVISION : 256 (64 sub-divisions × 4 months)
ZONE : 8 (2 zones × 4 months)

Pass criteria: All 6 levels present. Total docs = ~1,148. No other levels exist.


Test 2: All months covered

Verify all 4 months from the transformer collection are represented.

printjson(db.getCollection("audit-summaries").distinct("month").sort());

Expected output:

["2025-09", "2025-10", "2025-11", "2025-12"]

Pass criteria: Exactly these 4 months, no extras (no dummy 2026-01, 2026-02).


Test 3: MESCOM totalTCCount matches transformer count

Cross-validate the top-level counts against the source collection.

print("=== Transformer counts (source of truth) ===");
db.transformer.aggregate([
{ $group: { _id: "$month", count: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]).forEach(r => print(r._id, ":", r.count));

print("");
print("=== MESCOM audit-summary totalTCCount ===");
db.getCollection("audit-summaries")
.find({ level: "MESCOM" }, { month: 1, totalTCCount: 1, _id: 0 })
.sort({ month: 1 })
.forEach(r => print(r.month, ":", r.totalTCCount));

Pass criteria: For each month, MESCOM.totalTCCount === transformer.countDocuments({ month }).

Expected values:

2025-09 : 100392
2025-10 : 100501
2025-11 : 102327
2025-12 : 102583

Test 4: Invariant — auditedCount + failedCount === totalTCCount

Check this invariant holds for every single document in the collection.

var broken = db.getCollection("audit-summaries").find({
$expr: { $ne: [{ $add: ["$auditedCount", "$failedCount"] }, "$totalTCCount"] }
}).toArray();

print("Docs violating invariant:", broken.length);
if (broken.length > 0) {
broken.slice(0, 5).forEach(d =>
print(d.level, d.month, d.location,
"audited:", d.auditedCount, "failed:", d.failedCount, "total:", d.totalTCCount)
);
}

Pass criteria: broken.length === 0. No document should violate this.


Test 5: Invariant — sum of loss buckets === auditedCount

Every audited TC must land in exactly one loss bucket.

var broken = db.getCollection("audit-summaries").find({
$expr: {
$ne: [
{ $add: [
"$lossBuckets.belowMinus5", "$lossBuckets.minus5to0",
"$lossBuckets.zeroTo5", "$lossBuckets.fiveTo10",
"$lossBuckets.tenTo15", "$lossBuckets.fifteenTo20",
"$lossBuckets.above20"
]},
"$auditedCount"
]
}
}).toArray();

print("Docs where lossBucket sum != auditedCount:", broken.length);
if (broken.length > 0) {
broken.slice(0, 5).forEach(d =>
print(d.level, d.month, JSON.stringify(d.location),
"auditedCount:", d.auditedCount,
"bucketSum:", Object.values(d.lossBuckets).reduce((a, b) => a + b, 0))
);
}

Pass criteria: broken.length === 0.


Test 6: Roll-up consistency — SECTION sums match higher levels

Verify that summing SECTION docs produces the same totals as each higher level.

var fields = ["totalTCCount", "auditedCount", "failedCount"];
var levels = [
{ level: "SUB_DIVISION", groupKey: "location.subDivisionCode" },
{ level: "DIVISION", groupKey: "location.divisionCode" },
{ level: "CIRCLE", groupKey: "location.circleCode" },
{ level: "ZONE", groupKey: "location.zoneCode" },
{ level: "MESCOM", groupKey: null },
];

var months = db.getCollection("audit-summaries").distinct("month");
var pass = true;

months.forEach(month => {
levels.forEach(({ level, groupKey }) => {
// Sum sections grouped by the level's key
var groupId = groupKey ? "$" + groupKey : null;
var sectionSums = {};
db.getCollection("audit-summaries").aggregate([
{ $match: { level: "SECTION", month } },
{ $group: {
_id: groupId,
totalTCCount: { $sum: "$totalTCCount" },
auditedCount: { $sum: "$auditedCount" },
failedCount: { $sum: "$failedCount" },
}},
]).forEach(r => { sectionSums[r._id || "ALL"] = r; });

// Get actual level docs
db.getCollection("audit-summaries")
.find({ level, month })
.forEach(doc => {
var key = groupKey ? doc.location[groupKey.split(".")[1]] : "ALL";
var expected = sectionSums[key];
if (!expected) {
print("FAIL:", level, month, key, "- no matching section sum");
pass = false;
return;
}
fields.forEach(f => {
if (doc[f] !== expected[f]) {
print("FAIL:", level, month, key, f, "expected:", expected[f], "got:", doc[f]);
pass = false;
}
});
});
});
});

print(pass ? "PASS: All roll-up sums match" : "FAIL: Some roll-up sums do not match");

Pass criteria: Prints PASS: All roll-up sums match.


Test 7: Cross-validate MESCOM auditedCount and failedCount against transformer

Directly count AUDITED and AUDIT_FAILED transformers and compare with MESCOM docs.

var pass = true;

db.getCollection("audit-summaries").find({ level: "MESCOM" }).sort({ month: 1 }).forEach(doc => {
var audited = db.transformer.countDocuments({ month: doc.month, auditStatus: "AUDITED" });
var failed = db.transformer.countDocuments({ month: doc.month, auditStatus: "AUDIT_FAILED" });

if (doc.auditedCount !== audited) {
print("FAIL:", doc.month, "auditedCount expected:", audited, "got:", doc.auditedCount);
pass = false;
}
if (doc.failedCount !== failed) {
print("FAIL:", doc.month, "failedCount expected:", failed, "got:", doc.failedCount);
pass = false;
}
print(doc.month, "- audited:", doc.auditedCount, "(expected", audited + ")",
"failed:", doc.failedCount, "(expected", failed + ")");
});

print(pass ? "PASS" : "FAIL");

Pass criteria: All months show matching counts. Prints PASS.


Test 8: Cross-validate loss buckets against transformer (spot-check one month)

Pick 2025-09 and count transformers in each loss range directly, then compare with the MESCOM summary.

var month = "2025-09";
var match = { month, auditStatus: "AUDITED" };

var expected = {
belowMinus5: db.transformer.countDocuments({ ...match, lossPercentage: { $lt: -5 } }),
minus5to0: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: -5, $lt: 0 } }),
zeroTo5: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: 0, $lt: 5 } }),
fiveTo10: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: 5, $lt: 10 } }),
tenTo15: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: 10, $lt: 15 } }),
fifteenTo20: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: 15, $lt: 20 } }),
above20: db.transformer.countDocuments({ ...match, lossPercentage: { $gte: 20 } }),
};

var mescom = db.getCollection("audit-summaries").findOne({ level: "MESCOM", month });
var pass = true;

Object.keys(expected).forEach(k => {
var match = mescom.lossBuckets[k] === expected[k];
if (!match) pass = false;
print(k, "- expected:", expected[k], "got:", mescom.lossBuckets[k], match ? "OK" : "FAIL");
});

print(pass ? "PASS" : "FAIL");

Pass criteria: All 7 buckets match. Prints PASS.


Test 9: Cross-validate failed reasons against transformer (spot-check one month)

Pick 2025-09 and count failed transformers by each reason directly.

var month = "2025-09";
var match = { month, auditStatus: "AUDIT_FAILED" };

var expected = {
noMeterConstant: db.transformer.countDocuments({
...match, $or: [{ meterConstant: null }, { meterConstant: 0 }]
}),
withoutInstallationConsumption: db.transformer.countDocuments({
...match, $or: [{ installationConsumption: null }, { installationConsumption: 0 }]
}),
noTcConsumptionWithRemarks: db.transformer.countDocuments({
...match, tcConsumption: null, remark: { $ne: null }
}),
noTcConsumptionNoRemarks: db.transformer.countDocuments({
...match, tcConsumption: null, remark: null
}),
};

var mescom = db.getCollection("audit-summaries").findOne({ level: "MESCOM", month });
var pass = true;

Object.keys(expected).forEach(k => {
var match = mescom.failedReasons[k] === expected[k];
if (!match) pass = false;
print(k, "- expected:", expected[k], "got:", mescom.failedReasons[k], match ? "OK" : "FAIL");
});

print(pass ? "PASS" : "FAIL");

Pass criteria: All 4 reasons match. Prints PASS.


Test 10: Spot-check a single SECTION against direct transformer aggregation

Pick one specific section and month, compute its summary directly from transformers, and compare with the stored audit-summary doc.

var month = "2025-09";
var sectionCode = "1"; // NR- KAIKAMBA

// Direct aggregation on transformer
var direct = db.transformer.aggregate([
{ $match: { month, "location.sectionCode": sectionCode } },
{ $group: {
_id: null,
totalTCCount: { $sum: 1 },
auditedCount: { $sum: { $cond: [{ $eq: ["$auditStatus", "AUDITED"] }, 1, 0] } },
failedCount: { $sum: { $cond: [{ $eq: ["$auditStatus", "AUDIT_FAILED"] }, 1, 0] } },
belowMinus5: { $sum: { $cond: [{ $and: [{ $eq: ["$auditStatus", "AUDITED"] }, { $lt: ["$lossPercentage", -5] }] }, 1, 0] } },
above20: { $sum: { $cond: [{ $and: [{ $eq: ["$auditStatus", "AUDITED"] }, { $gte: ["$lossPercentage", 20] }] }, 1, 0] } },
noTcConsumptionNoRemarks: { $sum: { $cond: [{ $and: [{ $eq: ["$auditStatus", "AUDIT_FAILED"] }, { $eq: ["$tcConsumption", null] }, { $eq: ["$remark", null] }] }, 1, 0] } },
}}
]).toArray()[0];

// Stored audit-summary
var stored = db.getCollection("audit-summaries").findOne({
level: "SECTION", month, "location.sectionCode": sectionCode
});

print("=== Section", sectionCode, "Month", month, "===");
print("totalTCCount - direct:", direct.totalTCCount, "stored:", stored.totalTCCount);
print("auditedCount - direct:", direct.auditedCount, "stored:", stored.auditedCount);
print("failedCount - direct:", direct.failedCount, "stored:", stored.failedCount);
print("belowMinus5 - direct:", direct.belowMinus5, "stored:", stored.lossBuckets.belowMinus5);
print("above20 - direct:", direct.above20, "stored:", stored.lossBuckets.above20);
print("noTcNoRemarks - direct:", direct.noTcConsumptionNoRemarks, "stored:", stored.failedReasons.noTcConsumptionNoRemarks);

var pass = direct.totalTCCount === stored.totalTCCount
&& direct.auditedCount === stored.auditedCount
&& direct.failedCount === stored.failedCount
&& direct.belowMinus5 === stored.lossBuckets.belowMinus5
&& direct.above20 === stored.lossBuckets.above20
&& direct.noTcConsumptionNoRemarks === stored.failedReasons.noTcConsumptionNoRemarks;

print(pass ? "PASS" : "FAIL");

Pass criteria: All fields match between direct aggregation and stored doc. Prints PASS.


Test 11: No dummy data remains

Verify no documents with fake location codes or months outside the transformer data exist.

var dummyCodes = db.getCollection("audit-summaries").countDocuments({
$or: [
{ "location.zoneCode": "ZN-001" },
{ "location.circleCode": "CIR-001" },
{ "location.divisionCode": "DIV-001" },
{ "location.subDivisionCode": "SD-001" },
{ month: { $in: ["2026-01", "2026-02"] } },
]
});

print("Dummy docs remaining:", dummyCodes);
print(dummyCodes === 0 ? "PASS" : "FAIL");

Pass criteria: dummyCodes === 0.


Test 12: Location hierarchy completeness

Verify that every SECTION doc has all parent location codes populated (not null).

var incomplete = db.getCollection("audit-summaries").countDocuments({
level: "SECTION",
$or: [
{ "location.sectionCode": null },
{ "location.subDivisionCode": null },
{ "location.divisionCode": null },
{ "location.circleCode": null },
{ "location.zoneCode": null },
]
});

print("SECTION docs with missing parent codes:", incomplete);
print(incomplete === 0 ? "PASS" : "FAIL");

Pass criteria: incomplete === 0. Every section doc must have the full hierarchy.


Test Summary

#TestWhat it validates
1Doc count per levelCorrect number of docs at each hierarchy level
2All months coveredNo missing months, no dummy months
3MESCOM totalTCCount vs transformerTop-level count matches source collection
4audited + failed === totalCore invariant holds for every doc
5Loss bucket sum === auditedCountEvery audited TC is in exactly one bucket
6Roll-up consistencySECTION sums match SUB_DIVISION, DIVISION, CIRCLE, ZONE, MESCOM
7MESCOM audited/failed vs transformerDirect count validation against source
8Loss buckets vs transformerBucket boundaries produce correct counts
9Failed reasons vs transformerFailed classification logic is correct
10Single section spot-checkEnd-to-end validation for one section
11No dummy data remainsOld fake data is fully removed
12Location hierarchy completenessNo null parent codes in SECTION docs

All 12 tests must print PASS for the script to be considered successful.