Skip to content

2.8.0

Choose a tag to compare

@peterver peterver released this 03 Jan 15:08
· 4 commits to main since this release

Added

feat: Added withTransaction to the main Mongo instance. This wrapper simplifies ACID-compliant operations by automatically handling session creation, committing, and aborting (rollback) on errors.

const db = new Mongo({ ... });
const accounts = db.query('accounts');

try {
    // Automatically handles commit/rollback based on promise resolution/rejection
    await db.withTransaction(async (session) => {
        // Step 1: Deduct from Alice
        const debit = await accounts.updateOne(
            { name: 'Alice', balance: { $gte: 50 } },
            { $inc: { balance: -50 } },
            { session } // ⚠️ Important: Pass session to every operation
        );

        if (!debit) throw new Error('Alice has insufficient funds');

        // Step 2: Add to Bob
        const credit = await accounts.updateOne(
            { name: 'Bob' },
            { $inc: { balance: 50 } },
            { session }
        );

        if (!credit) throw new Error('Bob not found');
    });
} catch (err) {
    console.error('Transaction aborted, no data changed:', err);
}
  • feat: Added exists(filter) to the Query class. This is a high-performance utility that internally applies limit: 1 to check for document existence without the overhead of fetching the document or counting all matches.
const UserQuery = db.query<UserDocument>('users');

// Efficiently check if an email is taken
if (await UserQuery.exists({ email: 'jane@example.com' })) {
    throw new Error('Email already in use');
}
  • feat: Added distinct(key, filter) to the Query class. Allows for retrieving unique values for a specific field across a collection, with optional filtering.
const ProductQuery = db.query<ProductDocument>('products');

// Get all unique categories for active products
const categories = await ProductQuery.distinct('category', { isActive: true });
console.log(categories); // ['Electronics', 'Clothing', 'Home']

Improved

  • feat: createIndex now supports specialized index types beyond standard ascending/descending. You can now use string literals for Text, Hashed, and Geospatial indexes. Supported types: 1 | -1 | 'text' | 'hashed' | '2dsphere' | '2d' | 'geoHaystack'
// Text Index (for search)
await db.createIndex('products', 'text_search_idx', 
    { title: 'text', description: 'text' }, 
    { weights: { title: 10, description: 1 } }
);

// Geospatial Index (for location queries)
await db.createIndex('restaurants', 'geo_location_idx', { 
    coordinates: '2dsphere' 
});

// Partial Filtered Index
await db.createIndex('users', 'email_unique_idx', 
    { email: 1 }, 
    { unique: true, partialFilterExpression: { email: { $exists: true } } }
);
  • deps: Upgrade @types/node to 24.10.4
  • deps: Upgrade @valkyriestudios/utils to 12.48.0
  • deps: Upgrade @valkyriestudios/validator to 10.11.0
  • deps: Upgrade @vitest/coverage-v8 to 4.0.16
  • deps: Upgrade eslint to 9.39.2
  • deps: Upgrade mongodb to 6.21.0
  • deps: Upgrade typescript to 5.9.3
  • deps: Upgrade typescript-eslint to 8.51.0
  • deps: Upgrade vitest to 4.0.16