Comparison of MongoDB native vs monSQLize extended functions

This document provides a detailed comparison of the functional differences between MongoDB's native driver and monSQLize to help you understand the additional value provided by monSQLize.

Quick comparison table

Feature CategoryMongoDB NativemonSQLizeMajor Enhancements
Query operationSmart cache, cursor paging, slow query log
INSERT OPERATIONBatched inserts with configurable chunking and slow-query monitoring
Update operationExplicit cache invalidation, complete error handling
Delete operationExplicit cache invalidation, slow query monitoring
Aggregation operationCache support, streaming processing
Execution PlanIntegrated into query chain
Cross-database accessManual switchingOne line of code switching
Cache ManagementTTL/LRU/explicit invalidation/multi-layer caching
Performance MonitoringConfiguration requiredOut-of-the-box slow query log

MongoDB native functions (full support)

monSQLize fully encapsulates all native functions of MongoDB. You can use the familiar MongoDB API:

Complete CRUD operation

OperationsMethodsNative SupportDocumentation
CreateinsertOne, insertManyinsertOne guide, insertMany guide
Readfind, findOne, aggregate, count, distinctfind guide, findOne guide
UpdateupdateOne, updateMany, replaceOneupdateOne guide, updateMany guide
DeletedeleteOne, deleteManydeleteOne guide, deleteMany guide

Atomic operations

MethodsNative SupportDocumentation
findOneAndUpdatefindOneAndUpdate guide
findOneAndReplacefindOneAndReplace guide
findOneAndDeletefindOneAndDelete guide

Index management

MethodsNative SupportDocumentation
createIndex, createIndexesIndex creation guide
listIndexesIndex listing guide
dropIndex, dropIndexesIndex drop guide

All query options

OptionsNative supportDescription
projectionField projection
sortsort
limit / skippaging
hintIndex hints
collationsorting rules
maxTimeMSOperation timed out
commentOperation comments

monSQLize’s unique extension functions

Based on MongoDB's native functions, monSQLize provides additional convenience and performance optimization:


1. Intelligent caching system

MongoDB native: no cache

//MongoDB native: query the database every time
const db = client.db('shop');
const products = await db.collection('products').find({
  category: 'electronics'
}).toArray();
//Latency depends on the query, indexes, dataset, server, and network.

//Query again: still query the database
const products2 = await db.collection('products').find({
  category: 'electronics'
}).toArray();
//This still performs a database round trip.

monSQLize: smart caching

//monSQLize: automatic caching
const products = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }  //Cache for 5 seconds
);
//The first call queries the database and populates the configured cache.

//Query again: return from cache
const products2 = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
//The second call can return from cache while the entry remains valid.

Comparison of cache features

FeaturesMongoDB nativemonSQLize
Query CacheNoneTTL + LRU
Explicit invalidationNonePer-write cache.invalidate / autoInvalidate when configured
Namespace IsolationNoneIsolate by instance/database/collection
Concurrent deduplicationNonePrevent cache breakdown
Cache StatisticsNoneHit Rate/Number of Eliminations
Multi-tier cachingNoneLocal + Redis

Detailed documentation: Cache system

Performance note: A cache hit avoids the database query, but the resulting latency depends on serialization, cache tier, payload size, network placement, and contention. Measure the workload you deploy; see Performance evidence.


2. Explicit cache invalidation

MongoDB native: Manual cache management

//Requires manual management of cache consistency
const cache = new Map();

//Manually check cache when querying
const cacheKey = 'products:electronics';
let products = cache.get(cacheKey);

if (!products) {
  products = await db.collection('products').find({
    category: 'electronics'
  }).toArray();
  cache.set(cacheKey, products);
}

//Manually clear the cache when updating (easy to miss)
await db.collection('products').insertOne({
  name: 'New Product',
  category: 'electronics'
});

//The relevant cache must be cleared manually
cache.delete('products:electronics');  //Easy to forget or incomplete cleaning

monSQLize: explicit cache invalidation

// monSQLize: cache a read query
const products = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
// The read cache has been created.

// Insert new data and precisely clear the affected cached query.
await collection('products').insertOne(
  {
    name: 'New Product',
    category: 'electronics'
  },
  {
    cache: {
      invalidate: [{
        operation: 'find',
        query: { category: 'electronics' },
        options: { cache: 5000 }
      }]
    }
  }
);

// Query again: the declared cache entry has been invalidated.
const freshProducts = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
// The invalidation scope is declared on the write operation.

Operations supported by explicit invalidation

OperationsMongoDB nativemonSQLize
insertOne / insertManyManual invalidationExplicit invalidation
updateOne / updateManyManual invalidationExplicit invalidation
deleteOne / deleteManyManual invalidationExplicit invalidation
replaceOneManual invalidationExplicit invalidation
findOneAndUpdateManual invalidationExplicit invalidation
findOneAndReplaceManual invalidationExplicit invalidation
findOneAndDeleteManual invalidationExplicit invalidation

Benefits: Keep the invalidation scope close to the write path and avoid unexpected broad cache deletes.


3. Depth paging (cursor paging)

MongoDB native: offset/limit paging (poor performance)

// MongoDB native: use skip + limit (deep paging is slow)
const page = 1000;  //Page 1000
const pageSize = 20;

const products = await db.collection('products')
  .find({ category: 'electronics' })
  .sort({ createdAt: -1 })
  .skip((page - 1) * pageSize)  // Skip 19980 documents (very slow)
  .limit(pageSize)
  .toArray();

// Problem:
// - skip requires scanning all previous documents (performance decreases linearly with the number of pages)
// - Page 1000 needs to scan 19980 documents, which is very slow
// - Paging results are unstable when data changes (insertions/deletions affect subsequent pages)

Performance comparison:

Number of pagesskip + limit time consumingperformance
Page 110msFast
Page 10050msSlower
Page 1000500msVery slow
Page 100005000msNot available

monSQLize: Cursor paging (stable performance)

// monSQLize: use cursor paging (deep paging is also fast)
const page1 = await collection('products').findPage(
  { category: 'electronics' },
  {
    limit: 20,
    sort: { createdAt: -1 },
    bookmarks: {
      step: 10,      // Cache a bookmark every 10 pages
      maxHops: 20    // Jump up to 20 times
    }
  }
);

// Jump to page 1000 (jump via bookmark, no need to scan all data)
const page1000 = await collection('products').findPage(
  { category: 'electronics' },
  {
    limit: 20,
    page: 1000,    // Skip directly to page 1000
    bookmarks: { step: 10, maxHops: 20 }
  }
);

// Performance:
// - Skip through bookmarks to avoid scanning large amounts of data
// - Bounded bookmark hops when the configured bookmark is available
// - Data changes do not affect existing pages (the cursor locks the data set at query time)

Performance comparison:

Scenarioskip + limitmonSQLize cursor paging
Shallow pageSimple and usually sufficientAdds cursor/bookmark state
Deep sequential pagingServer work can grow with the skipped offsetContinues from a cursor boundary
Deep page jumpCost depends on the offset and query planUses configured bookmarks and bounded hops when a bookmark is available

Do not treat these characteristics as fixed speedups. Benchmark the actual indexes, selectivity, document size, page depth, concurrency, and MongoDB deployment; see Performance evidence.

Comparison of paging features

FeaturesMongoDB native (skip/limit)monSQLize (cursor paging)
Deep paging performanceLinear decline with the number of pagesStable performance (bookmark jump)
Flip forward and backwardSupportSupport (after/before)
Jump pageSupported (but slow)Supported (and fast)
Total statisticsNeed to be queried separatelyAsynchronous statistics (no blocking)
Data StabilityInsertion/deletion affects pagingCursor locked data set

Detailed documentation: findPage guide


4. Performance monitoring (slow query log)

MongoDB native: profiling needs to be configured

// MongoDB native: requires manual profiling configuration
await db.setProfilingLevel(1, { slowms: 100 });

// View the slow query log (requires querying system.profile separately)
const slowQueries = await db.collection('system.profile')
  .find({ millis: { $gt: 100 } })
  .toArray();

// Problem:
// - Requires manual configuration
// - Logs are stored in the database (occupying space)
// - Requires separate query and analysis
// - Slow-query warnings cannot be seen directly in the code

monSQLize: Slow query log out of the box

// monSQLize: automatically monitor slow queries
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' },
  slowQueryMs: 1000  // Log warning after 1 second (default)
});

// Automatically monitor slow query events
msq.on('slow-query', (data) => {
  console.warn('Slow query warning:', {
    operation: data.operation,
    collection: data.collectionName,
    duration: data.duration,
    query: data.query,
    options: data.options
  });
});

// Execute queries (automated monitoring)
const products = await collection('products').find({
  category: 'electronics'
});

// If the query takes more than 1 second, the slow-query event is automatically triggered.
// Output: Slow query warning: { operation: 'find', collection: 'products', duration: 1200, ... }

Comparison of performance monitoring features

FeaturesMongoDB nativemonSQLize
Slow Query MonitoringRequires profiling configurationReady to use out of the box
Real-time AlarmNeed to check the log separatelyEvents are automatically triggered
Query TimeoutmaxTimeMSGlobal + Query Level
Operation time consumingRequires profilingAutomatic recording
Log StorageOccupies database spaceApplication layer logs

Detailed documentation: Event system


5. Cross-database access

MongoDB native: Manually switch databases

// MongoDB native: switch databases manually
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();

// Access the shop database
const shopDb = client.db('shop');
const products = await shopDb.collection('products').find({}).toArray();

// Access the analytics database (requires manual switching)
const analyticsDb = client.db('analytics');  // Manual switching
const events = await analyticsDb.collection('events').find({}).toArray();

// Problem:
// - Each cross-database access needs a manual switch
// - Verbose code
// - Error-prone

monSQLize: scoped access across databases

// monSQLize: cross-database access with an explicit scoped accessor
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',  // Default database
  config: { uri: 'mongodb://localhost:27017' }
});

const { collection, use } = await msq.connect();

// Access the default database (shop)
const products = await collection('products').find({});

// Access analytics with a scoped database accessor
const events = await use('analytics').collection('events').find({});
// Concise and clear for business collection access

// Chained cross-database access
const logs = await use('logs').collection('access_logs').find({});

Comparison of cross-database access features

FeaturesMongoDB nativemonSQLize
Cross-database switchingManual client.db(name)Scoped collection access with use(name)
Default databaseNo conceptAutomatically use the default database
Code SimplicityLengthyConcise
Cache IsolationNo cacheAutomatic isolation by database

Detailed documentation: Connection configuration


6. Type Safety (TypeScript)

MongoDB native: generic types

//MongoDB native: basic generic types
import { MongoClient, Collection } from 'mongodb';

interface Product {
  _id?: ObjectId;
  name: string;
  price: number;
}

const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('shop');
const products: Collection<Product> = db.collection('products');

//Basic type inference
const result = await products.findOne({ name: 'iPhone' });
// result: Product | null

monSQLize: complete type declaration

//monSQLize: Complete TypeScript types
import MonSQLize from 'monsqlize';

interface Product {
  _id?: ObjectId;
  name: string;
  price: number;
  category: string;
}

const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' }
});

const { collection } = await msq.connect();

//Type-safe queries
const products = await collection('products').find<Product>(
  { category: 'electronics' },
  {
    cache: 5000,         //Option type check
    projection: { name: 1, price: 1 },  //Projection type check
    limit: 20            //Parameter type checking
  }
);
// products: Product[]

//Option autocomplete
const result = await collection('products').findPage<Product>(
  { category: 'electronics' },
  {
    cache: 5000,
    bookmarks: {
      step: 10,          //IDE auto-completion
      maxHops: 20,       //Type tips
      ttlMs: 3600000     //Type checking
    }
  }
);

TypeScript supports comparison

FeaturesMongoDB nativemonSQLize
Basic typesGenerics supportFull type declaration
Option TypePartial SupportFull Support
IDE CompletionBasic CompletionFull Completion
Type CheckPartial CheckStrict Check

Type declaration file: types/index.d.ts


7. Batch insert performance optimization

MongoDB native: standard insertMany

//MongoDB native: standard insertMany
const documents = Array.from({ length: 10000 }, (_, i) => ({
  index: i,
  name: `Product ${i}`,
  price: Math.random() * 1000
}));

//One-time insert (may timeout or run out of memory)
const result = await db.collection('products').insertMany(documents);
//Latency and memory use depend on payload size and deployment limits.

monSQLize: Intelligent batch insertion

//monSQLize: insertMany (automatic optimization)
const documents = Array.from({ length: 10000 }, (_, i) => ({
  index: i,
  name: `Product ${i}`,
  price: Math.random() * 1000
}));

//Standard insertMany (performance optimized)
const result = await collection('products').insertMany(documents);
//Uses the package write path; benchmark it against the same driver options.

//Very large batches: use insertBatch (automatic batching)
const result2 = await collection('products').insertBatch(documents, {
  batchSize: 1000  //1000 pieces per batch
});
//Limits each batch; failures and timeouts are still possible and must be handled.

Batch insert trade-offs

ScenarioMongoDB driver insertManymonSQLize insertManymonSQLize insertBatch
Fits one request comfortablyDirect driver pathPackage write path with its validation and hooksExtra batching overhead is usually unnecessary
Large or bounded requestsCaller chooses the chunking strategyOne package-level requestConfigurable batches bound work per request
Failure handlingDriver result and errorsPackage result and errorsPer-batch policy and partial-result handling

Chunking improves control over request size; it does not guarantee a universal throughput gain. Benchmark identical write concern, ordered mode, indexes, document sizes, and concurrency; see Performance evidence.

Detailed documentation: insertMany guide, insertBatch guide


8. Multi-layer caching (local + Redis)

MongoDB native: no cache (8. Multi-layer cache (local + Redis))

//MongoDB native: query the database every time
const products = await db.collection('products').find({
  category: 'electronics'
}).toArray();
//Every call reaches the database; latency is workload-dependent.

monSQLize: multi-layer caching

//monSQLize: local memory + Redis multi-layer cache
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' },

  cache: {
    multiLevel: true,
    local: { maxEntries: 10000 },  //Local cache 10,000 items
    remote: MonSQLize.createRedisCacheAdapter('redis://localhost:6379/0')
  }
});

//The first call queries MongoDB and populates the configured tiers.
const products1 = await collection('products').find(
  { category: 'electronics' },
  { cache: 10000 }
);

//The second call can hit the process-local cache.
const products2 = await collection('products').find(
  { category: 'electronics' },
  { cache: 10000 }
);

//If the local entry expires while Redis remains valid, read from Redis.

Multi-layer cache performance characteristics

Cache layerMain cost factorsExpected boundary
Database queryQuery plan, indexes, storage, server load, and networkAuthoritative data path
Redis cacheNetwork, serialization, payload size, Redis load, and topologyAvoids the MongoDB query but still performs a remote call
Local cacheSerialization, payload size, eviction, and process loadAvoids network calls within the current process

Compare these paths with the same payload and concurrency in your deployment; see Performance evidence.

Comparison of multi-layer cache features

FeaturesMongoDB nativemonSQLize
Local CacheNoneMemory LRU
Remote CacheNoneRedis Support
Multi-tier cachingNoneLocal + Redis
Auto BackfillNoneBackfill local on Redis hit
Cache ConsistencyNonePer-write explicit invalidation or configured broad invalidation

Detailed documentation: Multi-layer caching


9. Chain call API

MongoDB native: cursor chain call

//MongoDB native: cursor chain call
const cursor = db.collection('products')
  .find({ category: 'electronics' })
  .sort({ price: -1 })
  .skip(20)
  .limit(10);

const products = await cursor.toArray();

monSQLize: complete chain call + cache

//monSQLize: chained calls + cache support
const products = await collection('products')
  .find({ category: 'electronics' })
  .sort({ price: -1 })
  .skip(20)
  .limit(10)
  .cache(5000)        //Chain cache
  .maxTimeMS(3000)    //✅Chain timeout
  .comment('API:listProducts')  //✅Chained comments
  .toArray();

Comparison of chain call features

FeaturesMongoDB nativemonSQLize
Basic chainingfind/sort/limitFull support
Cache ChainNone.cache()
Timeout ChainingRequired in find option.maxTimeMS()
Comment chainingRequired in find option.comment()
Streaming chain.stream().stream() + cache

Detailed documentation: Chain query API


10. Event system

MongoDB native: listening to driver events

//MongoDB native: listening to underlying driver events
client.on('commandStarted', (event) => {
  console.log('Command:', event.commandName);
});

client.on('serverHeartbeatFailed', (event) => {
  console.error('Heartbeat failed');
});

//Question:
//- Only low-level driver events
//- No slow query events
//- No cache related events

monSQLize: rich business events

//monSQLize: business-level events
msq.on('slow-query', (data) => {
  console.warn('Slow query:', data.operation, data.duration);
});

msq.on('cache-hit', (data) => {
  console.log('Cache hit:', data.key);
});

msq.on('cache-miss', (data) => {
  console.log('Cache miss:', data.key);
});

msq.on('connected', () => {
  console.log('Database is connected');
});

msq.on('error', (data) => {
  console.error('Error:', data.error.message);
});

Event system comparison

Event typeMongoDB nativemonSQLize
Connection Event
DRIVING EVENT
Slow Query Event
Cache Event
Business Event

Detailed documentation: Event system


Usage suggestions

When to use MongoDB native driver?

Suitable scene:

  • Simple script or tool
  • No caching required
  • No advanced pagination required
  • Low performance requirements

When to use monSQLize?

Suitable scene:

  • Production Application - Requires caching and performance optimization
  • High Traffic API - Caching can reduce database pressure
  • Deep Pagination - list page, search results, etc.
  • Multi-database application - requires cross-database access
  • Performance Monitoring - Slow query alarm required
  • Complex Business - Requires declared cache invalidation boundaries

Summary and comparison

DimensionsMongoDB nativemonSQLizeBoost
Functional Completeness100% Compatible + Extensions
Performance (No Cache)Configurable write batching
Performance (With Cache)☆☆☆☆Local and remote cache tiers
Deep Paging☆☆☆Cursor and bookmark strategies
Ease of UseSimpler API
MaintainabilityExplicit cache invalidation
Observability☆☆☆Out-of-the-box monitoring

Quick Start

If you want to experience the extended capabilities of monSQLize, start here:

  1. Installation: npm install monsqlize
  2. Enable cache: Add { cache: 5000 } to the query
  3. Use paging: Use findPage() instead of find()
  4. Monitor slow query: Listen for slow-query events
  5. Cross-database access: use use(name).collection(name) for business collections; reserve db(name) for database-level commands

Full example: View the getting started guide