Utils/db_tool/main.js

269 lines
7.0 KiB
JavaScript

import { exec, spawn } from "child_process";
import { readdir } from "fs/promises";
import inquirer from "inquirer";
import moment from "moment";
import { MongoClient } from "mongodb";
const prompt = inquirer.createPromptModule();
const getDirectories = async source =>
(await readdir(source, { withFileTypes: true }))
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
async function performBackup(databaseName, uri) {
try {
const timestamp = moment().format("DD.MM.YYYY_HHmmss");
const { backupFolder } = await prompt([
{
type: "input",
name: "backupFolder",
message: "Enter the backup folder path (leave empty for default):",
default: `${databaseName}_${timestamp}`,
},
]);
const folderName = "dumps/" + backupFolder;
let backupCommand = spawn("mongodump", [
"--authenticationDatabase=admin",
"--uri",
uri,
"--db",
databaseName,
"--out",
folderName,
]);
backupCommand.stdout.on("data", function (data) {
console.log(data.toString());
});
backupCommand.stderr.on("data", function (data) {
console.log(data.toString());
});
const waitForEnd = new Promise((resolve, reject) => {
backupCommand.on("exit", function (code) {
console.log("child process exited with code " + code.toString());
console.log(`Search you backup in folder ${folderName}.`);
resolve();
});
});
await waitForEnd;
return;
} catch (error) {
console.error("An error occurred during the backup process:", error);
return;
}
}
async function performRestore(restoreFolder, uri) {
try {
console.log(`Restoring database from folder ${restoreFolder}...`);
let restoreCommand = spawn("mongorestore", ["--uri", uri, "--drop", restoreFolder]);
restoreCommand.stdout.on("data", function (data) {
console.log(data.toString());
});
restoreCommand.stderr.on("data", function (data) {
console.log(data.toString());
});
const waitForEnd = new Promise((resolve, reject) => {
restoreCommand.on("exit", function (code) {
console.log("child process exited with code " + code.toString());
resolve();
});
});
await waitForEnd;
return;
} catch (error) {
console.error("An error occurred during the restore process:", error);
return;
}
}
function generateConnectionString({ username, password, host, port }) {
let credentials = "";
if (username && password) {
credentials = `${username}:${password}@`;
}
const uri = `mongodb://${credentials}${host}:${port}`;
return uri;
}
async function chooseCollection(client) {
const { databaseName } = await prompt([
{
type: "list",
name: "databaseName",
message: "Choose a database:",
choices: await client
.db()
.admin()
.listDatabases()
.then(({ databases }) => databases.map(({ name }) => name)),
},
]);
const db = await client.db(databaseName);
let collectionList = await db.listCollections().toArray();
const collections = collectionList.map(c => c.name);
const { collectionName } = await prompt([
{
type: "list",
name: "collectionName",
message: "Choose a collection:",
choices: collections,
},
]);
const collection = db.collection(collectionName);
return collection;
}
async function chooseField(collection) {
const { fieldName } = await prompt([
{
type: "input",
name: "fieldName",
message: "Enter a field name:",
},
]);
return fieldName;
}
async function clearColleciton(collection) {
const result = await collection.deleteMany({});
console.log(result.deletedCount + " documents deleted");
}
async function clearField(collection, field) {
try {
const result = await collection.updateMany({}, { $unset: { [field]: "" } });
console.log(result.modifiedCount + " documents updated. Deleted field " + field);
} catch (err) {
console.log(err);
}
}
async function main() {
try {
const credentials = await prompt([
{
type: "input",
name: "username",
message: "Enter your MongoDB username:",
},
{
type: "password",
name: "password",
message: "Enter your MongoDB password:",
},
{
type: "input",
name: "host",
message: "Enter the MongoDB host:",
default: "localhost",
},
{
type: "input",
name: "port",
message: "Enter the MongoDB port:",
default: "27017",
},
]);
const uri = generateConnectionString(credentials);
const client = new MongoClient(uri);
await client.connect();
console.log("Connected to MongoDB successfully.");
while (true) {
const { action } = await prompt([
{
type: "list",
name: "action",
message: "Choose an action:",
choices: ["Clear ...", "Backup", "Restore"],
},
]);
if (action === "Backup") {
const { databaseName } = await prompt([
{
type: "list",
name: "databaseName",
message: "Choose a database to backup:",
choices: await client
.db()
.admin()
.listDatabases()
.then(({ databases }) => databases.map(({ name }) => name)),
},
]);
await performBackup(databaseName, uri);
} else if (action === "Restore") {
try {
const dirs = await getDirectories("./dumps");
const { restoreFolder } = await prompt([
{
type: "list",
name: "restoreFolder",
message: "Choose the folder to restore from:",
choices: dirs,
},
]);
await performRestore("./dumps/" + restoreFolder, uri);
} catch (err) {
if (err.errno === -2) {
console.log("No 'dumps' dir found");
} else {
throw new Error(err);
}
console.log("Disconnected from MongoDB.");
await client.close();
return;
}
} else if (action === "Clear ...") {
const { subject } = await prompt([
{
type: "list",
name: "subject",
message: "Choose what you are going to clean up:",
choices: ["collection", "field"],
},
]);
if (subject === "collection") {
const collection = await chooseCollection(client);
await clearColleciton(collection);
} else if (subject === "field") {
const collection = await chooseCollection(client);
const field = await chooseField(client);
await clearField(collection, field);
}
await client.close();
console.log("Disconnected from MongoDB.");
}
console.log("\nPress Ctrl+C to exit\n");
}
} catch (error) {
console.error("An error occurred:", error);
}
}
await main();