6 Commits

18 changed files with 2985 additions and 13680 deletions
Binary file not shown.
+68
View File
@@ -0,0 +1,68 @@
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
# * For C, use cpp
# * For JavaScript, use typescript
# Special requirements:
# * csharp: Requires the presence of a .sln file in the project folder.
language: typescript
# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true
# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed) on 2025-04-07
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
project_name: "mongodump"
+39
View File
@@ -0,0 +1,39 @@
{
"@git.zone/cli": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "mongodump",
"description": "A tool to create and manage dumps of MongoDB databases, supporting data export and import.",
"npmPackagename": "@push.rocks/mongodump",
"license": "MIT",
"keywords": [
"mongodb",
"database backup",
"data dump",
"database restore",
"mongodb export",
"mongodb import",
"database management",
"mongodb management",
"data backup",
"data recovery"
]
},
"release": {
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
],
"accessLevel": "public"
}
},
"@git.zone/tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": [],
"npmRegistryUrl": "registry.npmjs.org"
}
}
+21
View File
@@ -1,5 +1,26 @@
# Changelog # Changelog
## 2026-05-01 - 1.1.1 - fix(mongodb)
modernize MongoDB dump handling and filesystem integration
- replace smartdata-based test fixture generation with direct MongoDB client inserts
- migrate dump output from smartfile to smartfs and clean target directories safely before export
- improve descriptor handling and shutdown logic with optional credentials, stricter typing, and parallel client close
## 2025-08-18 - 1.1.0 - feat(MongoDumpTarget)
Implement core MongoDumpTarget methods and update documentation & project configs
- Implemented MongoDumpTarget.createAndInit(), init(), getCollections(), dumpCollectionToDir() and dumpAllCollectionsToDir() with connection handling, collection enumeration and file output.
- Added safe directory handling (ensureDir / ensureEmptyDir) and document-to-file writing using smartfile.memory.toFs and smartpath transformation.
- Enhanced README with detailed usage examples, API reference and best practices.
- Added local project configuration files (.claude/settings.local.json and .serena/project.yml) to support tooling and project metadata.
## 2025-08-18 - 1.0.10 - fix(mongodump.plugins)
Bump @types/node to ^22.0.0 and use runtime import for @tsclass/tsclass in plugins
- Bumped dev dependency @types/node from ^17.0.40 to ^22.0.0 in package.json
- Changed import of @tsclass/tsclass from a type-only import to a runtime import in ts/mongodump.plugins.ts so tsclass is exported and available at runtime
## 2025-08-18 - 1.0.9 - fix(dependencies) ## 2025-08-18 - 1.0.9 - fix(dependencies)
Update dependencies, normalize package scopes to @push.rocks, bump mongodb to v6, adjust tests and add pnpm metadata Update dependencies, normalize package scopes to @push.rocks, bump mongodb to v6, adjust tests and add pnpm metadata
+3 -1
View File
@@ -1,4 +1,6 @@
Copyright (c) 2022 Lossless GmbH (hello@lossless.com) The MIT License (MIT)
Copyright (c) 2026 Task Venture Capital GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+13 -7
View File
@@ -1,5 +1,5 @@
{ {
"gitzone": { "@git.zone/cli": {
"projectType": "npm", "projectType": "npm",
"module": { "module": {
"githost": "code.foss.global", "githost": "code.foss.global",
@@ -8,7 +8,6 @@
"description": "A tool to create and manage dumps of MongoDB databases, supporting data export and import.", "description": "A tool to create and manage dumps of MongoDB databases, supporting data export and import.",
"npmPackagename": "@push.rocks/mongodump", "npmPackagename": "@push.rocks/mongodump",
"license": "MIT", "license": "MIT",
"projectDomain": "push.rocks",
"keywords": [ "keywords": [
"mongodb", "mongodb",
"database backup", "database backup",
@@ -21,13 +20,20 @@
"data backup", "data backup",
"data recovery" "data recovery"
] ]
},
"release": {
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
],
"accessLevel": "public"
} }
}, },
"npmci": { "@git.zone/tsdoc": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n" "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": [],
"npmRegistryUrl": "registry.npmjs.org"
} }
} }
-10943
View File
File diff suppressed because it is too large Load Diff
+46 -41
View File
@@ -1,49 +1,22 @@
{ {
"name": "@push.rocks/mongodump", "name": "@push.rocks/mongodump",
"version": "1.0.9", "version": "1.1.1",
"private": false, "private": false,
"description": "A tool to create and manage dumps of MongoDB databases, supporting data export and import.", "description": "A tool to create and manage dumps of MongoDB databases, supporting data export and import.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
"type": "module", "type": "module",
"author": "Lossless GmbH", "author": "Task Venture Capital GmbH <hello@task.vc>",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "(tstest test/ --verbose)", "test": "tstest test/ --verbose",
"build": "(tsbuild --web --allowimplicitany)" "build": "tsbuild --web",
"format": "gitzone format",
"buildDocs": "tsdoc"
}, },
"devDependencies": { "repository": {
"@git.zone/tsbuild": "^2.1.25", "type": "git",
"@git.zone/tsbundle": "^2.0.5", "url": "https://code.foss.global/push.rocks/mongodump.git"
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.4",
"@push.rocks/smartdata": "^5.0.5",
"@push.rocks/smartmongo": "^2.0.3",
"@types/node": "^17.0.40"
},
"browserslist": [
"last 1 chrome versions"
],
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"dependencies": {
"@push.rocks/lik": "^6.0.0",
"@push.rocks/smartfile": "^11.2.7",
"@push.rocks/smartjson": "^5.0.6",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.0.2",
"@tsclass/tsclass": "^9.2.0",
"mongodb": "^6.18.0"
}, },
"keywords": [ "keywords": [
"mongodb", "mongodb",
@@ -57,10 +30,42 @@
"data backup", "data backup",
"data recovery" "data recovery"
], ],
"homepage": "https://code.foss.global/push.rocks/mongodump", "bugs": {
"repository": { "url": "https://gitlab.com/push.rocks/mongodump/issues"
"type": "git",
"url": "https://code.foss.global/push.rocks/mongodump.git"
}, },
"packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748" "homepage": "https://code.foss.global/push.rocks/mongodump",
"devDependencies": {
"@git.zone/tsbuild": "^4.4.0",
"@git.zone/tsrun": "^2.0.3",
"@git.zone/tstest": "^3.6.3",
"@push.rocks/smartmongo": "^7.0.0",
"@types/lodash.clonedeep": "^4.5.9",
"@types/node": "^25.6.0"
},
"browserslist": [
"last 1 chrome versions"
],
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
".smartconfig.json",
"license",
"npmextra.json",
"readme.md"
],
"dependencies": {
"@push.rocks/lik": "^6.4.1",
"@push.rocks/smartfs": "^1.5.1",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@tsclass/tsclass": "^9.5.1",
"mongodb": "^7.2.0"
},
"packageManager": "pnpm@10.28.2"
} }
+2467 -2555
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,2 +1,4 @@
onlyBuiltDependencies: onlyBuiltDependencies:
- esbuild - esbuild
- mongodb-memory-server
- puppeteer
+222 -39
View File
@@ -1,76 +1,259 @@
# @push.rocks/mongodump # @push.rocks/mongodump
a tool to handle dumps of MongoDB databases
## Install **A powerful MongoDB backup and restore tool** 🚀
To use @push.rocks/mongodump in your project, run:
[![npm version](https://img.shields.io/npm/v/@push.rocks/mongodump.svg)](https://www.npmjs.com/package/@push.rocks/mongodump)
[![license](https://img.shields.io/npm/l/@push.rocks/mongodump.svg)](https://www.npmjs.com/package/@push.rocks/mongodump)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
[![ES Module](https://img.shields.io/badge/ES%20Module-Ready-green.svg)](https://nodejs.org/api/esm.html)
## What it does 🎯
`@push.rocks/mongodump` is your go-to solution for creating and managing MongoDB database dumps. Whether you're backing up critical production data, migrating between environments, or implementing disaster recovery strategies, this tool has got your back. It provides a clean, TypeScript-based API for:
- 📦 **Full database backups** - Export entire MongoDB databases
- 🗂️ **Collection-level dumps** - Selectively backup specific collections
- 🏷️ **Custom naming** - Transform document names during export
- 🗜️ **Archive support** - Create compressed tar archives of your dumps
- 🔄 **Async/await patterns** - Modern promise-based workflow
- 🎨 **TypeScript first** - Full type safety and IntelliSense support
## Installation 💻
```bash ```bash
# Using npm
npm install @push.rocks/mongodump --save npm install @push.rocks/mongodump --save
# Using pnpm (recommended)
pnpm add @push.rocks/mongodump
# Using yarn
yarn add @push.rocks/mongodump
``` ```
## Usage ## Quick Start 🚀
This guide provides an overview of how to work with @push.rocks/mongodump to handle dumps of MongoDB databases efficiently. Get up and running in seconds:
### Setting up a MongoDB Dump Target ```typescript
First, you'll need to describe your MongoDB database using an interface provided by the module. Here's a sample descriptor: import { MongoDump } from '@push.rocks/mongodump';
import type { IMongoDescriptor } from '@tsclass/tsclass';
// Define your MongoDB connection
const mongoDescriptor: IMongoDescriptor = {
mongoDbName: 'my-database',
mongoDbUser: 'admin',
mongoDbPass: 'secure-password',
mongoDbUrl: 'mongodb+srv://cluster.mongodb.net',
};
// Create a dump of your entire database
const mongoDump = new MongoDump();
const target = await mongoDump.addMongoTargetByMongoDescriptor(mongoDescriptor);
await target.dumpAllCollectionsToDir('./backups/my-backup');
// Done! Your backup is ready 🎉
await mongoDump.stop();
```
## Detailed Usage 📚
### Setting Up MongoDB Connection
The module uses MongoDB descriptors to establish connections. This approach provides flexibility and security:
```typescript ```typescript
import { IMongoDescriptor } from '@tsclass/tsclass'; import { IMongoDescriptor } from '@tsclass/tsclass';
import { MongoDump, MongoDumpTarget } from '@push.rocks/mongodump'; import { MongoDump, MongoDumpTarget } from '@push.rocks/mongodump';
const myMongoDescriptor: IMongoDescriptor = { const mongoDescriptor: IMongoDescriptor = {
mongoDbName: '<database_name>', mongoDbName: 'production_db',
mongoDbUser: '<database_user>', mongoDbUser: process.env.MONGO_USER,
mongoDbPass: '<database_password>', mongoDbPass: process.env.MONGO_PASS,
mongoDbUrl: 'mongodb+srv://<user>:<password>@<cluster_url>/<dbname>?retryWrites=true&w=majority', mongoDbUrl: process.env.MONGO_URL,
}; };
``` ```
### Creating and Using the MongoDump Instance ### Working with MongoDump
To interact with MongoDB for dumping purposes, you'll use the `MongoDump` class:
The `MongoDump` class is your main entry point for managing database dumps:
```typescript ```typescript
async function setupMongoDump() { const mongoDump = new MongoDump();
const mongoDump = new MongoDump();
const mongoDumpTarget = await mongoDump.addMongoTargetByMongoDescriptor(myMongoDescriptor);
// mongoDumpTarget can now be used for further operations // Add a MongoDB target
} const dumpTarget = await mongoDump.addMongoTargetByMongoDescriptor(mongoDescriptor);
setupMongoDump();
// The target is now ready for dump operations
``` ```
### Dumping Collections to a Directory ### Dumping Collections
To dump the collections of a database into a directory with files representing each document, you can use the `dumpCollectionToDir` method. This method is useful for creating backups or migrating data:
#### Dump All Collections to Directory
Perfect for complete database backups:
```typescript ```typescript
async function dumpCollections() { // Basic dump - uses document _id as filename
const mongoDump = new MongoDump(); await dumpTarget.dumpAllCollectionsToDir('./backups/full-backup');
const mongoDumpTarget = await mongoDump.addMongoTargetByMongoDescriptor(myMongoDescriptor);
await mongoDumpTarget.dumpAllCollectionsToDir('./path/to/dumpDir', null, true); // Custom naming - use any document field for filenames
// This dumps all collections to the specified directory, cleaning the directory before dumping. await dumpTarget.dumpAllCollectionsToDir(
} './backups/named-backup',
dumpCollections(); (doc) => `${doc.username}_${doc.timestamp}`,
true // Clean directory before dumping
);
``` ```
### Advanced Dumping Options #### Dump Specific Collection
For more control over the dumping process, including naming conventions for dumped files or handling specific collections, you can explore methods like `dumpCollectionToDir` for individual collections and advanced configurations concerning directory cleanliness and document naming.
### Shutting Down Properly When you need granular control:
It's important to close down database connections properly once your dumping operations are complete:
```typescript ```typescript
async function shutDownMongoDump() { // Get available collections
const collections = await dumpTarget.getCollections();
console.log('Available collections:', collections);
// Dump a specific collection
const userCollection = collections.find(c => c.collectionName === 'users');
await dumpTarget.dumpCollectionToDir(
userCollection,
'./backups/users',
(doc) => doc.email.replace('@', '_at_') // Custom naming
);
```
### Archive Support
Create compressed archives for efficient storage and transfer:
```typescript
// Dump to tar archive file
await dumpTarget.dumpCollectionToTarArchiveFile(
userCollection,
'./backups/users.tar.gz'
);
// Or work with streams for advanced scenarios
const archiveStream = await dumpTarget.dumpAllCollectionsToTarArchiveStream();
// Pipe to S3, network storage, etc.
```
### Advanced Patterns
#### Scheduled Backups
Implement automated backup strategies:
```typescript
import { CronJob } from 'cron';
const backupJob = new CronJob('0 0 * * *', async () => {
const timestamp = new Date().toISOString().split('T')[0];
const mongoDump = new MongoDump(); const mongoDump = new MongoDump();
const target = await mongoDump.addMongoTargetByMongoDescriptor(mongoDescriptor);
await target.dumpAllCollectionsToDir(
`./backups/daily/${timestamp}`,
null,
true
);
await mongoDump.stop(); await mongoDump.stop();
// Closes all open database connections gracefully console.log(`✅ Daily backup completed: ${timestamp}`);
} });
shutDownMongoDump();
backupJob.start();
``` ```
### Conclusion #### Multiple Database Targets
The @push.rocks/mongodump module provides a flexible approach to handling MongoDB database dumps, whether it's for backup, migration, or other purposes. By leveraging TypeScript and modern async patterns, it integrates smoothly into modern Node.js applications focused on MongoDB interactions.
Handle multiple databases simultaneously:
```typescript
const mongoDump = new MongoDump();
// Add multiple targets
const prodTarget = await mongoDump.addMongoTargetByMongoDescriptor(prodDescriptor);
const stagingTarget = await mongoDump.addMongoTargetByMongoDescriptor(stagingDescriptor);
// Dump both in parallel
await Promise.all([
prodTarget.dumpAllCollectionsToDir('./backups/production'),
stagingTarget.dumpAllCollectionsToDir('./backups/staging')
]);
await mongoDump.stop();
```
#### Error Handling
Implement robust error handling:
```typescript
try {
const mongoDump = new MongoDump();
const target = await mongoDump.addMongoTargetByMongoDescriptor(mongoDescriptor);
await target.dumpAllCollectionsToDir('./backups/safe-backup');
console.log('✅ Backup successful');
} catch (error) {
console.error('❌ Backup failed:', error);
// Implement notification/retry logic
} finally {
await mongoDump.stop();
}
```
### Clean Shutdown
Always ensure proper cleanup of database connections:
```typescript
// Closes all open MongoDB connections
await mongoDump.stop();
```
## API Reference 🔧
### MongoDump
The main class for managing dump operations.
**Methods:**
- `addMongoTargetByMongoDescriptor(descriptor: IMongoDescriptor)`: Create a new dump target
- `stop()`: Close all database connections
### MongoDumpTarget
Handles operations for a specific MongoDB database.
**Methods:**
- `getCollections()`: List all collections in the database
- `dumpCollectionToDir(collection, directory, nameTransform?)`: Dump single collection
- `dumpAllCollectionsToDir(directory, nameTransform?, cleanDir?)`: Dump all collections
- `dumpCollectionToTarArchiveFile(collection, filepath)`: Create tar archive
- `dumpAllCollectionsToTarArchiveStream()`: Get tar archive stream
## Best Practices 💡
1. **Environment Variables**: Store credentials in environment variables, never hardcode them
2. **Error Handling**: Always wrap dump operations in try-catch blocks
3. **Connection Cleanup**: Always call `stop()` when done
4. **Backup Verification**: Periodically verify your backups can be restored
5. **Storage Rotation**: Implement backup rotation to manage disk space
6. **Monitoring**: Add logging and monitoring for production backup jobs
## Why Choose @push.rocks/mongodump? 🌟
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Modern Async**: Built on promises and async/await patterns
- **Flexible Export**: Multiple export formats and naming options
- **Production Ready**: Battle-tested in production environments
- **Clean API**: Intuitive, well-documented interface
- **Active Maintenance**: Regular updates and security patches
## License and Legal Information ## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
+44 -41
View File
@@ -1,49 +1,52 @@
import * as smartdata from '@push.rocks/smartdata'; import * as mongodb from 'mongodb';
import type * as tsclass from '@tsclass/tsclass';
let db: smartdata.SmartdataDb; let mongoClient: mongodb.MongoClient | undefined;
export const stop = async () => { export const stop = async () => {
await db.close(); await mongoClient?.close();
} mongoClient = undefined;
};
export const generateTestData = async (mongoDescriptorArg: smartdata.IMongoDescriptor) => { export const generateTestData = async (mongoDescriptorArg: tsclass.database.IMongoDescriptor) => {
db = new smartdata.SmartdataDb(mongoDescriptorArg); const finalConnectionUrl = mongoDescriptorArg.mongoDbUrl
await db.init(); .replace('<USERNAME>', mongoDescriptorArg.mongoDbUser ?? '')
let counter = 0; .replace('<username>', mongoDescriptorArg.mongoDbUser ?? '')
.replace('<USER>', mongoDescriptorArg.mongoDbUser ?? '')
.replace('<user>', mongoDescriptorArg.mongoDbUser ?? '')
.replace('<PASSWORD>', mongoDescriptorArg.mongoDbPass ?? '')
.replace('<password>', mongoDescriptorArg.mongoDbPass ?? '')
.replace('<DBNAME>', mongoDescriptorArg.mongoDbName ?? '')
.replace('<dbname>', mongoDescriptorArg.mongoDbName ?? '');
mongoClient = await mongodb.MongoClient.connect(finalConnectionUrl);
const db = mongoClient.db(mongoDescriptorArg.mongoDbName);
const houseCollection = db.collection('House');
const truckCollection = db.collection('Truck');
@smartdata.Collection(db) const houseDocs: mongodb.OptionalUnlessRequiredId<mongodb.Document>[] = [];
class House extends smartdata.SmartDataDbDoc<House, House> { const truckDocs: mongodb.OptionalUnlessRequiredId<mongodb.Document>[] = [];
@smartdata.unI()
id = `hello-${counter}`;
@smartdata.svDb() for (let counter = 0; counter < 100; counter++) {
data = { houseDocs.push({
'some' : { id: `hello-${counter}`,
'complex': 'structure', data: {
more: 4 some: {
} complex: 'structure',
} more: 4,
},
},
});
truckDocs.push({
id: `hello-${counter}`,
data: {
some: {
complex: 'structure',
more: 2,
},
},
});
} }
@smartdata.Collection(db) await houseCollection.insertMany(houseDocs);
class Truck extends smartdata.SmartDataDbDoc<Truck, Truck> { await truckCollection.insertMany(truckDocs);
@smartdata.unI() };
id = `hello-${counter}`;
@smartdata.svDb()
data = {
'some' : {
'complex': 'structure',
more: 2
}
}
}
while (counter < 100) {
const house = new House();
await house.save();
const truck = new Truck();
await truck.save();
counter++;
}
}
+4 -4
View File
@@ -17,8 +17,8 @@ tap.test('should create a mongodump instance', async () => {
}); });
tap.test('should deploy sample data', async () => { tap.test('should deploy sample data', async () => {
await sampledata.generateTestData(await testSmartMongo.getMongoDescriptor()) await sampledata.generateTestData(await testSmartMongo.getMongoDescriptor());
}) });
tap.test('should add a mongotarget to mongodump instance', async () => { tap.test('should add a mongotarget to mongodump instance', async () => {
const target = await testMongodump.addMongoTargetByMongoDescriptor(await testSmartMongo.getMongoDescriptor()); const target = await testMongodump.addMongoTargetByMongoDescriptor(await testSmartMongo.getMongoDescriptor());
@@ -27,8 +27,8 @@ tap.test('should add a mongotarget to mongodump instance', async () => {
tap.test('should dump a collection to a directory', async () => { tap.test('should dump a collection to a directory', async () => {
const target = await testMongodump.addMongoTargetByMongoDescriptor(await testSmartMongo.getMongoDescriptor()); const target = await testMongodump.addMongoTargetByMongoDescriptor(await testSmartMongo.getMongoDescriptor());
await target.dumpAllCollectionsToDir('.nogit', docArg => docArg.id, true); await target.dumpAllCollectionsToDir('.nogit', (docArg) => String(docArg.id), true);
}) });
tap.test('should stop the smartmongo instance', async () => { tap.test('should stop the smartmongo instance', async () => {
await sampledata.stop(); await sampledata.stop();
+1 -1
View File
@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/mongodump', name: '@push.rocks/mongodump',
version: '1.0.9', version: '1.1.1',
description: 'A tool to create and manage dumps of MongoDB databases, supporting data export and import.' description: 'A tool to create and manage dumps of MongoDB databases, supporting data export and import.'
} }
+3 -3
View File
@@ -15,8 +15,8 @@ export class MongoDump {
} }
public async stop() { public async stop() {
await this.mongoTargetObjectMap.forEach(async (mongoTargetArg) => { await Promise.all(
await mongoTargetArg.mongoDbClient.close(); this.mongoTargetObjectMap.getArray().map((mongoTargetArg) => mongoTargetArg.mongoDbClient.close())
}) );
} }
} }
+34 -25
View File
@@ -1,5 +1,8 @@
import * as plugins from './mongodump.plugins.js'; import * as plugins from './mongodump.plugins.js';
type TMongoDumpDocument = plugins.mongodb.WithId<plugins.mongodb.Document>;
export type TMongoDumpNameTransform = (docArg: TMongoDumpDocument) => string;
/** /**
* a MongoDump Target is a pointer to a database * a MongoDump Target is a pointer to a database
* + exposes functions to interact with the dump target * + exposes functions to interact with the dump target
@@ -11,10 +14,12 @@ export class MongoDumpTarget {
return mongoDumpTarget; return mongoDumpTarget;
} }
public readyDeferred = plugins.smartpromise.defer(); public readyDeferred = plugins.smartpromise.defer<void>();
public mongoDescriptor: plugins.tsclass.database.IMongoDescriptor; public mongoDescriptor: plugins.tsclass.database.IMongoDescriptor;
public mongoDbClient: plugins.mongodb.MongoClient; public mongoDbClient!: plugins.mongodb.MongoClient;
public mongoDb: plugins.mongodb.Db; public mongoDb!: plugins.mongodb.Db;
public smartFs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
constructor(mongoDescriptorArg: plugins.tsclass.database.IMongoDescriptor) { constructor(mongoDescriptorArg: plugins.tsclass.database.IMongoDescriptor) {
this.mongoDescriptor = mongoDescriptorArg; this.mongoDescriptor = mongoDescriptorArg;
} }
@@ -22,16 +27,16 @@ export class MongoDumpTarget {
/** /**
* connects to the database that was specified during instance creation * connects to the database that was specified during instance creation
*/ */
public async init(): Promise<any> { public async init(): Promise<void> {
const finalConnectionUrl = this.mongoDescriptor.mongoDbUrl const finalConnectionUrl = this.mongoDescriptor.mongoDbUrl
.replace('<USERNAME>', this.mongoDescriptor.mongoDbUser) .replace('<USERNAME>', this.mongoDescriptor.mongoDbUser ?? '')
.replace('<username>', this.mongoDescriptor.mongoDbUser) .replace('<username>', this.mongoDescriptor.mongoDbUser ?? '')
.replace('<USER>', this.mongoDescriptor.mongoDbUser) .replace('<USER>', this.mongoDescriptor.mongoDbUser ?? '')
.replace('<user>', this.mongoDescriptor.mongoDbUser) .replace('<user>', this.mongoDescriptor.mongoDbUser ?? '')
.replace('<PASSWORD>', this.mongoDescriptor.mongoDbPass) .replace('<PASSWORD>', this.mongoDescriptor.mongoDbPass ?? '')
.replace('<password>', this.mongoDescriptor.mongoDbPass) .replace('<password>', this.mongoDescriptor.mongoDbPass ?? '')
.replace('<DBNAME>', this.mongoDescriptor.mongoDbName) .replace('<DBNAME>', this.mongoDescriptor.mongoDbName ?? '')
.replace('<dbname>', this.mongoDescriptor.mongoDbName); .replace('<dbname>', this.mongoDescriptor.mongoDbName ?? '');
this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, { this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
maxPoolSize: 100, maxPoolSize: 100,
@@ -60,47 +65,51 @@ export class MongoDumpTarget {
* dumps a collection to a directory * dumps a collection to a directory
*/ */
public async dumpCollectionToDir( public async dumpCollectionToDir(
collectionArg: plugins.mongodb.Collection, collectionArg: plugins.mongodb.Collection<plugins.mongodb.Document>,
dirArg: string, dirArg: string,
nameTransformFunction = (doc: any) => doc._id nameTransformFunction: TMongoDumpNameTransform = (docArg) => docArg._id.toString()
) { ) {
const dirPath = plugins.smartpath.transform.makeAbsolute(dirArg); const dirPath = plugins.smartpath.transform.makeAbsolute(dirArg);
const collectionDir = plugins.path.join(dirPath, collectionArg.collectionName); const collectionDir = plugins.path.join(dirPath, collectionArg.collectionName);
await plugins.smartfile.fs.ensureDir(collectionDir); await this.smartFs.directory(collectionDir).create();
const cursor = collectionArg.find(); const cursor = collectionArg.find();
let value = await cursor.next(); let value = await cursor.next();
while (value) { while (value) {
await plugins.smartfile.memory.toFs( const targetPath = plugins.path.join(collectionDir, `${nameTransformFunction(value)}.json`);
JSON.stringify(value, null, 2), await this.smartFs.file(targetPath).encoding('utf8').write(JSON.stringify(value, null, 2));
plugins.path.join(collectionDir, `${nameTransformFunction(value)}.json`)
);
value = await cursor.next(); value = await cursor.next();
} }
} }
public async dumpCollectionToTarArchiveStream(collectionArg: plugins.mongodb.Collection) {} public async dumpCollectionToTarArchiveStream(
collectionArg: plugins.mongodb.Collection<plugins.mongodb.Document>
) {}
public async dumpCollectionToTarArchiveFile( public async dumpCollectionToTarArchiveFile(
collectionArg: plugins.mongodb.Collection, collectionArg: plugins.mongodb.Collection<plugins.mongodb.Document>,
filePathArg: string filePathArg: string
) {} ) {}
public async dumpAllCollectionsToDir( public async dumpAllCollectionsToDir(
dirArg: string, dirArg: string,
nameFunctionArg?: (docArg: any) => string, nameFunctionArg?: TMongoDumpNameTransform,
cleanDirArg = false cleanDirArg = false
) { ) {
const dirPath = plugins.smartpath.transform.makeAbsolute(dirArg);
if (cleanDirArg) { if (cleanDirArg) {
await plugins.smartfile.fs.ensureEmptyDir(dirArg); if (await this.smartFs.directory(dirPath).exists()) {
await this.smartFs.directory(dirPath).recursive().delete();
}
await this.smartFs.directory(dirPath).create();
} }
const collections = await this.getCollections(); const collections = await this.getCollections();
for (const collection of collections) { for (const collection of collections) {
await this.dumpCollectionToDir(collection, dirArg, nameFunctionArg); await this.dumpCollectionToDir(collection, dirPath, nameFunctionArg);
} }
} }
public async dumpAllCollectionsToTarArchiveStream( public async dumpAllCollectionsToTarArchiveStream(
collectionArg: plugins.mongodb.Collection, collectionArg: plugins.mongodb.Collection<plugins.mongodb.Document>,
filePathArg: string filePathArg: string
) {} ) {}
} }
+11 -13
View File
@@ -2,34 +2,32 @@
import * as path from 'path'; import * as path from 'path';
export { export {
path path,
} };
// pushrocks scope // pushrocks scope
import * as lik from '@push.rocks/lik'; import * as lik from '@push.rocks/lik';
import * as smartfile from '@push.rocks/smartfile'; import * as smartfs from '@push.rocks/smartfs';
import * as smartjson from '@push.rocks/smartjson';
import * as smartpath from '@push.rocks/smartpath'; import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise'; import * as smartpromise from '@push.rocks/smartpromise';
export { export {
lik, lik,
smartfile, smartfs,
smartjson,
smartpath, smartpath,
smartpromise smartpromise,
} };
// tsclass // tsclass
import type * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';
export { export {
tsclass tsclass,
} };
// third party scope // third party scope
import * as mongodb from 'mongodb'; import * as mongodb from 'mongodb';
export { export {
mongodb mongodb,
} };
+4 -4
View File
@@ -5,10 +5,10 @@
"target": "ES2022", "target": "ES2022",
"module": "NodeNext", "module": "NodeNext",
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",
"noImplicitAny": true,
"esModuleInterop": true, "esModuleInterop": true,
"verbatimModuleSyntax": true "verbatimModuleSyntax": true,
"types": ["node"]
}, },
"exclude": [ "exclude": ["dist_*/**/*.d.ts"]
"dist_*/**/*.d.ts"
]
} }