@360-l/mongo-bulk-data-migration
Version:
MongoDB bulk data migration for node scripts
123 lines (122 loc) • 4.49 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractBulkOperationResults = exports.NO_COUNT_AVAILABLE = exports.INITIAL_BULK_INFOS = void 0;
const lodash_1 = __importDefault(require("lodash"));
exports.INITIAL_BULK_INFOS = {
insertedIds: [],
nInserted: 0,
nMatched: 0,
nModified: 0,
nRemoved: 0,
nUpserted: 0,
ok: 1,
upserted: [],
writeConcernErrors: [],
writeErrors: [],
};
exports.NO_COUNT_AVAILABLE = -1;
class AbstractBulkOperationResults {
collection;
results;
bulk;
totalBulkOps;
totalOperations;
logger;
constructor(collection, logger, totalOperations) {
this.collection = collection;
this.totalOperations = totalOperations;
this.logger = logger;
this.totalBulkOps = 0;
this.results = lodash_1.default.cloneDeep(exports.INITIAL_BULK_INFOS);
this.initialize();
}
get size() {
return this.totalBulkOps;
}
get progress() {
if (this.totalOperations === exports.NO_COUNT_AVAILABLE) {
return Infinity;
}
return (this.totalOperationsDone / this.totalOperations) * 100;
}
get totalOperationsDone() {
return (this.results.nMatched + this.results.nUpserted + this.results.nInserted);
}
initialize() {
this.bulk = this.collection.initializeUnorderedBulkOp();
this.totalBulkOps = 0;
return this;
}
async execute(continueOnBulkWriteError = false) {
if (this.totalBulkOps === 0) {
return this;
}
const bulkResponse = await this.bulk.execute().catch((err) => {
if (continueOnBulkWriteError &&
err?.constructor.name === 'MongoBulkWriteError') {
return err.result;
}
throw err;
});
const resultPartial = {
insertedIds: Object.values(bulkResponse.insertedIds),
nInserted: bulkResponse.insertedCount,
nMatched: bulkResponse.matchedCount,
nModified: bulkResponse.modifiedCount,
nRemoved: bulkResponse.deletedCount,
nUpserted: bulkResponse.upsertedCount,
ok: bulkResponse.ok,
upserted: Object.values(bulkResponse.upsertedIds),
writeConcernErrors: [bulkResponse.getWriteConcernError()].filter(isDefined),
writeErrors: bulkResponse.getWriteErrors(),
};
this.mergeResults(resultPartial);
this.logExecutionStatus(resultPartial);
return this.initialize();
}
mergeResults(resultB) {
this.results.nInserted += resultB.nInserted;
this.results.nMatched += resultB.nMatched;
this.results.nModified += resultB.nModified;
this.results.nRemoved += resultB.nRemoved;
this.results.nUpserted += resultB.nUpserted;
this.results.ok = this.results.ok && resultB.ok;
if (process.env.NODE_ENV === 'test') {
this.results.insertedIds.push(...resultB.insertedIds);
this.results.upserted.push(...resultB.upserted);
}
this.results.writeConcernErrors.push(...resultB.writeConcernErrors);
this.results.writeErrors.push(...resultB.writeErrors);
this.results.nMatched += resultB.writeErrors.length;
return this;
}
getResults() {
return this.results;
}
buildLogObject(executionResults) {
const usefulLogEntries = Object.entries(executionResults)
.filter(([key]) => !['insertedIds', 'upserted'].includes(key))
.filter(([, value]) => !lodash_1.default.isEmpty(value) || value > 0);
const progress = this.progress;
const formattedPercent = Number.isFinite(progress)
? progress.toFixed(2)
: 'N/A';
return {
...Object.fromEntries(usefulLogEntries),
progress: {
totalOperationsDone: this.totalOperationsDone,
estimatedTotalOperations: this.totalOperations === exports.NO_COUNT_AVAILABLE
? 'N/A'
: this.totalOperations,
percent: formattedPercent,
},
};
}
}
exports.AbstractBulkOperationResults = AbstractBulkOperationResults;
function isDefined(value) {
return value !== undefined;
}