cry-db MongoDB Wrapper
cry-db is a TypeScript-first MongoDB wrapper library, currently stable at version 2.4.31. Its versioning suggests active development, though a specific release cadence isn't published. It offers a high-level, opinionated API for common database operations, abstracting away direct MongoDB driver interactions. Key differentiators include built-in support for document revisions, soft-delete functionality, archiving, blocking, and auditing, which simplify complex data lifecycle management. The library also provides real-time publish events, enabling reactive applications. It offers two main interfaces: `Mongo` for flexible multi-collection operations and `Repo<T>` for type-safe, single-collection convenience. Connection details are automatically managed via `MONGO_URL` and `MONGO_DB` environment variables, streamlining setup. A central feature is its unique record lifecycle, where soft-deleted and archived records are filtered from standard queries by default, requiring explicit options to retrieve them.
Common errors
-
MongoServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017
cause The MongoDB server is not running or is not accessible at the configured `MONGO_URL` (often the default `mongodb://127.0.0.1:27017`).fixEnsure your MongoDB instance is running. Verify that `process.env.MONGO_URL` (or the explicit database name in the constructor) is correctly pointing to your MongoDB server address and port. -
Query returns no documents, but I know they exist.
cause Documents might be marked as soft-deleted (`_deleted`) or archived (`_archived`), and standard queries automatically filter these out by default.fixWhen calling query methods like `find` or `findOne`, pass `{ returnDeleted: true }` and/or `{ returnArchived: true }` in the options object to include these records in the results. Alternatively, use `findAll` which bypasses these filters.
Warnings
- gotcha When soft-delete (`_deleted`) or archiving (`_archived`) features are enabled, most query methods automatically filter out records marked as deleted or archived by default. This can lead to seemingly missing documents.
- gotcha The `deleteOne()` and `delete()` methods perform a *soft-delete* (setting the `_deleted` flag) if soft-delete is enabled for the `Repo` instance. They do not physically remove the document.
- gotcha Connection to MongoDB relies on `MONGO_URL` and `MONGO_DB` environment variables by default. If these are not set, the library will attempt to connect to `mongodb://127.0.0.1:27017` and use the default database name 'test'.
- gotcha When revisions are enabled (`useRevisions(true)`), every write operation (insert, update) automatically increments the `_rev` field and updates the `_ts` (timestamp) field on documents.
Install
-
npm install cry-db -
yarn add cry-db -
pnpm add cry-db
Imports
- Repo
const Repo = require('cry-db').Repo;import { Repo } from 'cry-db'; - Mongo
const Mongo = require('cry-db').Mongo;import { Mongo } from 'cry-db'; - ObjectId
import { Types } from 'cry-db'; // For ObjectIdimport { ObjectId } from 'cry-db';
Quickstart
import { Repo, Mongo, ObjectId } from 'cry-db';
// Ensure MongoDB is running and accessible via MONGO_URL and MONGO_DB environment variables.
// Example: process.env.MONGO_URL = 'mongodb://127.0.0.1:27017';
// Example: process.env.MONGO_DB = 'mytestdb';
async function runExample() {
// Repo — single-collection convenience class with type safety
const users = new Repo<{ _id?: ObjectId, name: string, age: number, active?: boolean }>('users', process.env.MONGO_DB || 'testdb');
// Mongo — multi-collection class for more granular control
const mongo = new Mongo(process.env.MONGO_DB || 'testdb');
console.log('--- Repo operations (users collection) ---');
// Insert a new user
let alice = await users.insert({ name: 'Alice', age: 30 });
console.log('Inserted Alice:', alice);
// Find Alice by name
let foundAlice = await users.findOne({ name: 'Alice' });
console.log('Found Alice:', foundAlice);
// Update Alice's age
await users.updateOne({ name: 'Alice' }, { $set: { age: 31 } });
let updatedAlice = await users.findOne({ name: 'Alice' });
console.log('Updated Alice:', updatedAlice);
// Demonstrate soft-delete (opt-in) and retrieval
await users.useSoftDelete(true); // Enable soft-delete for this Repo instance
if (updatedAlice?._id) {
await users.deleteOne({ _id: updatedAlice._id });
console.log('Soft-deleted Alice. Trying to find (should be null):', await users.findOne({ _id: updatedAlice._id }));
console.log('Finding deleted Alice (with returnDeleted):', await users.findOne({ _id: updatedAlice._id }, { returnDeleted: true }));
// Cleanup (hard delete to permanently remove)
await users.hardDeleteOne(updatedAlice._id);
}
console.log('Count after cleanup:', await users.count({}));
console.log('\n--- Mongo operations (products collection) ---');
// Mongo can operate on any collection without creating a dedicated Repo instance
const productsCollection = 'products';
let product1 = await mongo.insert(productsCollection, { name: 'Laptop', price: 1200 });
console.log('Inserted Laptop:', product1);
let foundProduct = await mongo.findOne(productsCollection, { name: 'Laptop' });
console.log('Found Laptop:', foundProduct);
// Clean up
if (product1?._id) {
await mongo.hardDelete(productsCollection, { _id: product1._id });
}
console.log('Hard-deleted Laptop.');
}
runExample().catch(console.error);