A MongoDB and Java List comparison tool for regression testing and data validation. Compare two collections or in-memory lists field-by-field, visualize differences in a dark-themed web UI, and export results to Excel.
- Two comparison modes — compare MongoDB collections directly or Java lists in-memory (no database required)
- Merge-join algorithm — efficient sorted-stream comparison, handles millions of records
- Field-level diff detection — identifies exact attributes that differ between matched records
- Four break types —
match,difference,onlyOnA,onlyOnB - React web UI — dark IDE-inspired interface with real-time progress, filtering, sorting, and drill-down
- Excel export — color-coded
.xlsxreports with summary, detail sheets, and smart cell merging - Session management — run multiple comparison sessions, track active sessions across users
- Built-in sample data — 215 pre-configured accounts with intentional differences for instant demo
The landing page where you create a new comparison session, load a demo, or load sample data directly from MongoDB or in-memory.
After loading data, the dashboard shows stat cards, real-time progress bars, and a sortable/filterable data grid with match/break percentages and status badges for every record.
Click any completed record to drill down into the field-by-field comparison. Baseline (A) values are highlighted in yellow, RC (B) values in green, and each difference is tagged by type.
View all active comparison sessions across your team from the slide-out panel on the right.
- Java 17+ (JDK)
- Maven 3.6+
- MongoDB 4.4+ (optional — only needed for MongoDB-mode comparisons)
mvn clean packagejava -jar target/comparison-app-1.0.0.jarThen open http://localhost:8080 in your browser.
MongoDiff works without a running MongoDB instance. Use the "Load Mongo Mem" button on the UI or call the in-memory API endpoint:
curl -X POST http://localhost:8080/api/sample/load-memThis compares 215 sample accounts entirely in-memory and returns the results to the UI.
┌──────────────────────────────────────────────────────────┐
│ Web Browser │
│ (React SPA at /) │
└────────────────────────┬─────────────────────────────────┘
│ REST API
┌────────────────────────▼─────────────────────────────────┐
│ Spring Boot Application │
│ ┌──────────────────────────────────────────────────┐ │
│ │ SampleDataController │ │
│ │ POST /api/sample/load (MongoDB mode) │ │
│ │ POST /api/sample/load-mem (in-memory mode) │ │
│ │ GET /api/sample/status │ │
│ │ GET /api/sample/breaks/{id} │ │
│ └───────────────┬──────────────────────┬────────────┘ │
│ │ │ │
│ ┌───────────────▼───────┐ ┌──────────▼────────────┐ │
│ │GenericComparisonService│ │ ExcelReportService │ │
│ │ │ │ │ │
│ │ compareCollections() │ │ generateExcelReport() │ │
│ │ compareLists() │ │ Summary + Detail sheets│ │
│ └───────────┬───────────┘ └────────────────────────┘ │
│ │ │
│ ┌───────────▼───────────┐ │
│ │ MongoTemplate │ (optional) │
│ └───────────┬───────────┘ │
└──────────────┼────────────────────────────────────────────┘
│
┌───────▼───────┐
│ MongoDB │
└───────────────┘
The GenericComparisonService uses a merge-join algorithm on sorted data:
- Both sources are sorted by a key attribute (e.g.
accountId) - Two iterators walk both collections simultaneously
- When keys match, each specified attribute is compared using
Objects.equals() - When keys don't match, the record is classified as
onlyOnAoronlyOnB - Results are stored as
ComparisonBreakrecords
This approach is O(n log n) for sorting + O(n) for the merge pass, making it efficient for large datasets.
| Endpoint | Method | Description |
|---|---|---|
/api/sample/load |
POST |
Load 215 sample accounts into MongoDB, compare, return results |
/api/sample/load-mem |
POST |
Same comparison done entirely in-memory (no MongoDB needed) |
/api/sample/status |
GET |
Get the status and results of the last comparison |
/api/sample/breaks/{id} |
GET |
Get field-level breaks for a specific record ID |
curl -s -X POST http://localhost:8080/api/sample/load-mem | jq '.session'{
"name": "Sample Comparison",
"startedAt": "2026-02-28T17:30:00Z",
"totalIds": 215
}curl -s http://localhost:8080/api/sample/breaks/acct0001 | jq .[
{
"comparisonKey": "acct0001",
"differenceField": "balance",
"valueInCollectionA": "1000.0",
"valueInCollectionB": "1010.0",
"breakType": "difference"
}
]The built-in sample generates 215 accounts with intentional differences:
| Range | Count | Behavior |
|---|---|---|
acct0001 – acct0030 |
30 | Present in both, balance differs (+10.0 in RC) |
acct0031 – acct0200 |
170 | Present in both, fully matching |
acct0201 – acct0205 |
5 | Only in Baseline (onlyOnA) |
acct0301 – acct0310 |
10 | Only in RC (onlyOnB) |
@Autowired GenericComparisonService comparisonService;
comparisonService.compareCollections(
Account.class,
"accountBaseline", // collection A
"accountRC", // collection B
"accountId", // key attribute
List.of("balance", "accountType", "riskLevel"), // attributes to compare
"comparisonBreaks" // output collection
);GenericComparisonService service = new GenericComparisonService();
ListComparisonResult<Account> result = service.compareLists(
baselineAccounts, // list A
rcAccounts, // list B
"accountId", // key attribute
List.of("balance", "accountType", "riskLevel")
);
System.out.println(result);
// List Comparison Summary:
// Items Processed from List A: 205
// Items Processed from List B: 210
// Keys Only in List A: 5
// Keys Only in List B: 10
// Common Keys Found: 200
// - Fully Matched Keys: 170
// - Keys with Attribute Mismatches: 30
// Total Individual Attribute Differences: 30@Autowired ExcelReportService excelService;
XSSFWorkbook workbook = excelService.generateExcelReport(
Account.class,
"accountId",
"accountBaseline",
"accountRC",
"comparisonBreaks"
);
try (FileOutputStream out = new FileOutputStream("report.xlsx")) {
workbook.write(out);
}The generated Excel workbook contains four sheets:
| Sheet | Contents |
|---|---|
| Summary | Count of each break type (onlyOnA, onlyOnB, difference) |
| onlyOnA | Full records that exist only in Baseline |
| onlyOnB | Full records that exist only in RC |
| difference | Side-by-side values with yellow (A) and green (B) highlighting |
src/main/resources/application.yaml
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mongodiff
auto-index-creation: false
logging:
level:
org.springframework: INFO
com.example.comparison: DEBUGIf MongoDB is not available, the application still starts — the in-memory comparison mode works without it.
Run all in-memory tests (no MongoDB required):
mvn test -Dtest="GenericComparisonServiceListTest,GenericComparisonServiceLargeScaleTest"Run all tests including embedded MongoDB tests:
mvn test| Test Class | What It Covers |
|---|---|
GenericComparisonServiceTest |
Core comparison with embedded MongoDB |
GenericComparisonServiceListTest |
In-memory list comparison |
GenericComparisonServiceLargeScaleTest |
Large dataset handling (1M+ items) |
GenericComparisonServiceCarTest |
Comparison with Car entity |
ExcelReportServiceTest |
Excel report generation |
mongodiff/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/com/example/comparison/
│ │ │ ├── ComparisonApplication.java # Spring Boot entry point
│ │ │ ├── controller/
│ │ │ │ └── SampleDataController.java # REST API
│ │ │ ├── model/
│ │ │ │ ├── Account.java # Financial account entity
│ │ │ │ ├── Car.java # Vehicle entity
│ │ │ │ ├── ComparisonBreak.java # Diff result record
│ │ │ │ └── MyEntity.java # Generic example
│ │ │ └── service/
│ │ │ ├── GenericComparisonService.java # Comparison engine
│ │ │ └── ExcelReportService.java # Excel export
│ │ └── resources/
│ │ ├── application.yaml
│ │ └── static/
│ │ └── index.html # React UI (single-file)
│ └── test/
│ └── java/com/example/comparison/
│ ├── GenericComparisonServiceTest.java
│ ├── GenericComparisonServiceListTest.java
│ ├── GenericComparisonServiceLargeScaleTest.java
│ └── service/
│ └── ExcelReportServiceTest.java
└── .github/
└── workflows/
└── ci.yml # GitHub Actions CI
| Component | Technology |
|---|---|
| Runtime | Java 17 |
| Framework | Spring Boot 3.2.5 |
| Database | MongoDB (optional) |
| Excel | Apache POI 5.2.3 |
| Frontend | React 18 (CDN, single-file SPA) |
| Testing | JUnit 5 + Flapdoodle Embedded MongoDB |
| CI/CD | GitHub Actions |
MIT -- David Olivares, 2024



