Overview
monSQLize provides a set of practical utility methods for accessing internal state, obtaining configuration information, and namespace information. These methods help developers better understand and debug applications.
Core Features
- ✅ Cache instance access: Get the underlying cache instance for advanced operations
- ✅ Configuration Query: View the current default configuration and parameters
- ✅ Namespace Information: Get the complete namespace of a collection
API methods
getCache()
Obtain the underlying cache instance and support direct operation of the cache.
Method signature
const cache = msq.getCache()
Parameter description
No parameters.
Return value
CacheLike // MemoryCache, MultiLevelCache, Redis adapter, or a custom CacheLike
Cache instance method
Usage example
Basic usage
1. Get cache instance
import MonSQLize from 'monsqlize';
const msq = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' },
cache: {
maxEntries: 1000,
defaultTtl: 60000
}
});
await msq.connect();
const cache = msq.getCache();
console.log('Cache type:', cache.constructor.name);
2. View cache statistics
const cache = msq.getCache();
const stats = cache.getStats();
console.log('Cache statistics:', {
hits: stats.hits,
misses: stats.misses,
hitRate: `${(stats.hits / (stats.hits + stats.misses) * 100).toFixed(2)}%`,
cacheItems: stats.size,
memoryUsage: `${(stats.memoryUsage / 1024 / 1024).toFixed(2)} MB`
});
Example output:
{
Number of hits: 150,
Number of misses: 50,
Hit rate: '75.00%',
Number of cached items: 85,
Memory usage: '2.34 MB'
}
3. Manual cache operation
const { collection } = await msq.connect();
const cache = msq.getCache();
const cacheKey = 'custom:data:123';
await cache.set(cacheKey, { id: 123, name: 'Product A' }, 3600000); //1 hour
const cached = await cache.get(cacheKey);
console.log('Cached data:', cached);
await cache.del(cacheKey);
console.log('✅ Cache has been deleted');
4. Clear all caches
const cache = msq.getCache();
await cache.clear();
console.log('✅ All caches have been cleared');
const stats = cache.getStats();
console.log('Number of cached items:', stats.size); //should be 0
getDefaults()
Get the default configuration parameters of the current instance.
Method signature (getDefaults())
const defaults = msq.getDefaults()
Parameter description (getDefaults())
No parameters.
Return value (getDefaults())
{
type: 'mongodb',
databaseName: string | undefined,
maxTimeMS: number,
findLimit: number,
findMaxLimit: number,
findMaxSkip: number,
findPageMaxLimit: number,
autoConvertObjectId: boolean | object,
namespace: object,
slowQueryLog: object | false
}
Method 1: Use getNamespace() + cache.keys() combination (most convenient)
const { collection } = await msq.connect();
const cache = msq.getCache();
if (cache) {
//Get namespace information
const ns = collection('products').getNamespace();
console.log('Namespace:', ns); // { iid: '...', type: 'mongodb', db: 'shop', collection: 'products' }
//Build schemas using namespaces (more precise)
const pattern = `*"collection":"${ns.collection}"*"db":"${ns.db}"*`;
const productsCacheKeys = await cache.keys(pattern);
console.log('products collection cache information:');
console.log('Number of cache keys:', productsCacheKeys.length);
//View the contents of each cache key
for (const key of productsCacheKeys.slice(0, 5)) { //Show only first 5
const value = await cache.get(key);
console.log('Key:', key);
console.log('Value:', value ? `${value.length} documents` : 'null');
}
}
Method 2: Use the collection name directly (simple but possible cross-database matching)
const cache = msq.getCache();
if (cache) {
//Use only collection names (may match collections of the same name from other databases)
const productsCacheKeys = await cache.keys('*"collection":"products"*');
console.log('Products collection cache quantity:', productsCacheKeys.length);
}
Example output:
products collection cache information:
Number of cache keys: 12
Key: {"ns":{"p":"monSQLize","v":1,"iid":"...","type":"mongodb","db":"shop","collection":"products"},"op":"find","query":{"status":"active"}}
Value: 25 documents
Key: {"ns":{"p":"monSQLize","v":1,"iid":"...","type":"mongodb","db":"shop","collection":"products"},"op":"count","query":{}}
Value: null
...
6. Get the cache of a specific operation
const cache = msq.getCache();
if (cache) {
//Get cache keys for all find operations
const findCacheKeys = await cache.keys('*"op":"find"*');
console.log('Number of find operation caches:', findCacheKeys.length);
//Get cache keys for all count operations
const countCacheKeys = await cache.keys('*"op":"count"*');
console.log('count number of operation caches:', countCacheKeys.length);
//Get the find operation cache of the products collection
const productsFind = await cache.keys('*"collection":"products"*"op":"find"*');
console.log('products find cache quantity:', productsFind.length);
}
7. Analyze cache usage (simplified method ⭐)
const { collection } = await msq.connect();
const cache = msq.getCache();
if (cache) {
//Method 1: Use getNamespace() to get the exact namespace (recommended)
async function getCacheInfoByCollection(collectionName) {
const ns = collection(collectionName).getNamespace();
const pattern = `*"collection":"${ns.collection}"*"db":"${ns.db}"*`;
const allKeys = await cache.keys(pattern);
const info = {
collection: ns.collection,
database: ns.db,
total: allKeys.length,
operations: {}
};
//Statistics of various operation types
for (const key of allKeys) {
try {
const keyObj = JSON.parse(key);
const op = keyObj.op || 'unknown';
info.operations[op] = (info.operations[op] || 0) + 1;
} catch (e) {
//Ignore unresolved keys
}
}
return info;
}
//Get cached information for the products collection
const productsInfo = await getCacheInfoByCollection('products');
console.log('products cache information:', productsInfo);
//Get multiple collections in batches
const collections = ['products', 'users', 'orders'];
const allInfo = {};
for (const name of collections) {
allInfo[name] = await getCacheInfoByCollection(name);
}
console.log('All collection cache:', allInfo);
}
Example output:
products cache information: {
collection: 'products',
database: 'shop',
total: 15,
operations: { find: 8, count: 4, findOne: 3 }
}
all collection caches: {
products: { collection: 'products', database: 'shop', total: 15, operations: { find: 8, count: 4, findOne: 3 } },
users: { collection: 'users', database: 'shop', total: 8, operations: { find: 5, findOne: 3 } },
orders: { collection: 'orders', database: 'shop', total: 6, operations: { find: 4, count: 2 } }
}
const { collection } = await msq.connect();
const cache = msq.getCache();
//Encapsulated into tool class
class CacheManager {
constructor(msq) {
this.msq = msq;
this.cache = msq.getCache();
}
//Get collection cache information
async getCollectionCacheInfo(collectionName) {
if (!this.cache) return null;
const ns = this.msq.collection(collectionName).getNamespace();
const pattern = `*"collection":"${ns.collection}"*"db":"${ns.db}"*`;
const keys = await this.cache.keys(pattern);
return {
collection: ns.collection,
database: ns.db,
namespace: `${ns.db}.${ns.collection}`,
totalKeys: keys.length,
operations: this._groupByOperation(keys),
keys: keys
};
}
//Group by operation type
_groupByOperation(keys) {
const ops = {};
for (const key of keys) {
try {
const keyObj = JSON.parse(key);
const op = keyObj.op || 'unknown';
if (!ops[op]) ops[op] = [];
ops[op].push(key);
} catch (e) {
//ignore
}
}
return ops;
}
//Get global cache statistics
getGlobalStats() {
if (!this.cache) return null;
return this.cache.getStats();
}
//Get the cache distribution of all collections
async getAllCollectionsCacheInfo() {
if (!this.cache) return null;
const allKeys = await this.cache.keys('*');
const collectionsMap = {};
for (const key of allKeys) {
try {
const keyObj = JSON.parse(key);
const ns = keyObj.ns;
if (!ns || !ns.collection) continue;
const collKey = `${ns.db}.${ns.collection}`;
if (!collectionsMap[collKey]) {
collectionsMap[collKey] = {
database: ns.db,
collection: ns.collection,
totalKeys: 0,
operations: {}
};
}
collectionsMap[collKey].totalKeys++;
const op = keyObj.op || 'unknown';
collectionsMap[collKey].operations[op] =
(collectionsMap[collKey].operations[op] || 0) + 1;
} catch (e) {
//ignore
}
}
return collectionsMap;
}
}
//Usage example
const cacheManager = new CacheManager(msq);
//Get products cache information
const productsCache = await cacheManager.getCollectionCacheInfo('products');
console.log('products cache:', productsCache);
//Get global statistics
const globalStats = cacheManager.getGlobalStats();
console.log('Global cache statistics:', globalStats);
//Get the cache distribution of all collections
const allCollections = await cacheManager.getAllCollectionsCacheInfo();
console.log('All collection cache:', allCollections);
getDefaults() example
1. View the default configuration
import MonSQLize from 'monsqlize';
const msq = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' },
maxTimeMS: 5000,
findLimit: 50,
findPageMaxLimit: 200,
cache: {
maxEntries: 1000,
defaultTtl: 10000
}
});
await msq.connect();
//Get default configuration
const defaults = msq.getDefaults();
console.log('Default configuration:', defaults);
Example output:
{
maxTimeMS: 5000,
findLimit: 50,
findPageMaxLimit: 200,
namespace: { scope: 'database' }
}
2. Verify that the configuration takes effect
const { collection } = await msq.connect();
//Get default configuration
const defaults = msq.getDefaults();
//No parameters are specified when querying, and default values are used.
const products = await collection('products').find(
{ status: 'active' }
);
console.log(`Query results: ${products.length} documents`);
console.log(`Default limits applied: ${defaults.findLimit}`);
3. Debugging configuration issues
const defaults = msq.getDefaults();
//Check query timeout
if (defaults.maxTimeMS < 3000) {
console.warn(`⚠️Shorter query timeout: ${defaults.maxTimeMS}ms`);
}
//Check paging limits
if (defaults.findLimit > 100) {
console.warn(`⚠️ The default paging limit is large: ${defaults.findLimit}`);
}
4. Runtime configuration comparison
//Create multiple instances and compare configurations
const msq1 = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' },
findLimit: 20,
maxTimeMS: 3000
});
const msq2 = new MonSQLize({
type: 'mongodb',
databaseName: 'analytics',
config: { uri: 'mongodb://localhost:27017' },
findLimit: 100,
cache: { enabled: false }
});
await msq1.connect();
await msq2.connect();
console.log('Example 1 configuration:', msq1.getDefaults());
console.log('Example 2 configuration:', msq2.getDefaults());
//Output:
//Example 1 configuration includes { findLimit: 20, maxTimeMS: 3000 }
//Example 2 configuration includes { findLimit: 100 }
getNamespace()
Get the complete namespace of the collection (format: databaseName.collectionName).
Method signature (getNamespace())
const namespace = collection('collectionName').getNamespace()
Parameter description (getNamespace())
No parameters. Returns the namespace of the currently bound collection.
Return value (getNamespace())
string //Format: "databaseName.collectionName"
getNamespace() example
1. Get the namespace
import MonSQLize from 'monsqlize';
const msq = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' }
});
const { collection } = await msq.connect();
//Get namespace
const namespace = collection('products').getNamespace();
console.log('Namespace:', namespace); //Output: "shop.products"
2. Multiple collection namespaces
const { collection } = await msq.connect();
//Get the namespace of multiple collections
const collections = ['users', 'orders', 'products', 'logs'];
collections.forEach(name => {
const namespace = collection(name).getNamespace();
console.log(`Namespace of ${name}: ${namespace}`);
});
//Output:
//users namespace: shop.users
//Namespace of orders: shop.orders
//products namespace: shop.products
//Namespace of logs: shop.logs
3. Application of namespace in logs
const { collection } = await msq.connect();
//Record namespace before querying
const namespace = collection('products').getNamespace();
console.log(`[${new Date().toISOString()}] Query collection: ${namespace}`);
const result = await collection('products').find(
{ status: 'active' },
{ limit: 10 }
);
console.log(`[${new Date().toISOString()}] Query completed: ${namespace}, result: ${result.length} documents`);
//Output:
//[2025-11-06T10:30:00.000Z] Query collection: shop.products
//[2025-11-06T10:30:00.123Z] Query completed: shop.products, results: 10 documents
4. Namespace verification
const { collection } = await msq.connect();
//Verify namespace format
function validateNamespace(collectionName) {
const namespace = collection(collectionName).getNamespace();
const [dbName, colName] = namespace.split('.');
console.log(`Database name: ${dbName}`);
console.log(`Collection name: ${colName}`);
console.log(`Full namespace: ${namespace}`);
return { dbName, colName, namespace };
}
validateNamespace('products');
//Output:
//Database name: shop
//Collection name: products
//Full namespace: shop.products
5. Namespace when operating across databases
//Create two instances of different databases
const shopDB = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' }
});
const analyticsDB = new MonSQLize({
type: 'mongodb',
databaseName: 'analytics',
config: { uri: 'mongodb://localhost:27017' }
});
await shopDB.connect();
await analyticsDB.connect();
//Compare namespaces
const shopCollection = shopDB.collection('products');
const analyticsCollection = analyticsDB.collection('products');
console.log('Shop namespace:', shopCollection.getNamespace()); // shop.products
console.log('Analytics namespace:', analyticsCollection.getNamespace()); // analytics.products
Best Practices
1. Cache monitoring
Regularly monitor cache statistics and optimize cache strategies:
const cache = msq.getCache();
if (cache) {
//Periodically output cache statistics
setInterval(async () => {
const stats = cache.getStats();
const hitRate = (stats.hits / (stats.hits + stats.misses) * 100).toFixed(2);
console.log('Cache statistics:', {
hitRate: `${hitRate}%`,
cacheItems: stats.size,
memory: `${(stats.memoryUsage / 1024 / 1024).toFixed(2)} MB`
});
//If the hit rate is less than 50%, consider adjusting the cache strategy
if (parseFloat(hitRate) < 50) {
console.warn('⚠️ The cache hit rate is too low, it is recommended to optimize the cache strategy');
}
}, 60000); //Check every minute
}
1.1 Monitor the cache of a specific collection (using getNamespace ⭐)
const { collection } = await msq.connect();
const cache = msq.getCache();
if (cache) {
//Recommendation: Use getNamespace() to get the exact namespace
setInterval(async () => {
const ns = collection('products').getNamespace();
const pattern = `*"collection":"${ns.collection}"*"db":"${ns.db}"*`;
const productsKeys = await cache.keys(pattern);
//Statistics by operation type
const findKeys = await cache.keys(`${pattern}*"op":"find"*`);
const countKeys = await cache.keys(`${pattern}*"op":"count"*`);
const findOneKeys = await cache.keys(`${pattern}*"op":"findOne"*`);
console.log('products collection cache:', {
namespace: `${ns.db}.${ns.collection}`,
totalCacheKeys: productsKeys.length,
findOperations: findKeys.length,
countOperations: countKeys.length,
findOneOperations: findOneKeys.length
});
//If you have too many cache keys, you may need to adjust the TTL or cleanup policy
if (productsKeys.length > 100) {
console.warn('⚠️ There are too many cache keys in the products collection, it is recommended to shorten the TTL');
}
}, 60000);
}
2. Configuration verification
Verify the configuration is reasonable at startup:
const defaults = msq.getDefaults();
//Verify configuration rationality
function validateConfig(defaults) {
const warnings = [];
if (defaults.findLimit > 100) {
warnings.push(`findLimit is large (${defaults.findLimit}), which may affect broad queries`);
}
if (defaults.maxTimeMS < 1000) {
warnings.push(`maxTimeMS is too small (${defaults.maxTimeMS}), which may cause query timeout`);
}
if (defaults.findPageMaxLimit > defaults.findMaxLimit) {
warnings.push(`findPageMaxLimit should not exceed findMaxLimit`);
}
if (warnings.length > 0) {
console.warn('⚠️ Configuration warning:');
warnings.forEach(w => console.warn(` - ${w}`));
} else {
console.log('✅ Configuration verification passed');
}
}
validateConfig(defaults);
3. Namespace tracking
Use namespaces in logs to facilitate tracking:
const { collection } = await msq.connect();
//Encapsulate log function with namespace
function logWithNamespace(collectionName, level, message, data) {
const namespace = collection(collectionName).getNamespace();
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${level}] [${namespace}] ${message}`, data || '');
}
//Usage example
logWithNamespace('products', 'INFO', 'Start query', { query: { status: 'active' } });
const result = await collection('products').find(
{ status: 'active' },
{ limit: 10 }
);
logWithNamespace('products', 'INFO', 'Query completed', { count: result.length });
//Output:
//[2025-11-06T10:30:00.000Z] [INFO] [shop.products] Start query { query: { status: 'active' } }
//[2025-11-06T10:30:00.123Z] [INFO] [shop.products] Query completed { count: 10 }
4. Cache warm-up
Use getCache() to implement cache warm-up:
const { collection } = await msq.connect();
const cache = msq.getCache();
async function prewarmCache() {
console.log('Start cache warm-up...');
//Warm up popular products
const hotProducts = await collection('products').find(
{ featured: true },
{
limit: 100,
cache: 3600000 //1 hour
}
);
console.log(`✅ ${hotProducts.length} hot products have been preheated`);
//Warm up user configuration
const userConfigs = await collection('configs').find(
{ type: 'user' },
{
limit: 50,
cache: 7200000 //2 hours
}
);
console.log(`✅ ${userConfigs.length} user configurations have been warmed up`);
//Show cache statistics
const stats = cache.getStats();
console.log('Cache warm-up completed:', {
cacheItems: stats.size,
memoryUsage: `${(stats.memoryUsage / 1024 / 1024).toFixed(2)} MB`
});
}
await prewarmCache();
FAQ
Q1: How do I disable the runtime cache?
A: getCache() returns the active CacheLike instance. To disable storage while keeping the runtime API stable, configure the cache object with enabled: false:
const msq = new MonSQLize({
type: 'mongodb',
databaseName: 'shop',
config: { uri: 'mongodb://localhost:27017' },
cache: { enabled: false }
});
const cache = msq.getCache();
console.log(cache.constructor.name);
Q2: How to view the cache key of a query?
A: The cache key is automatically generated by the query parameters, the format is: <namespace>:<query-hash>
const { collection } = await msq.connect();
//The query automatically generates a cache key
const result = await collection('products').find(
{ status: 'active' },
{
limit: 10,
cache: 5000
}
);
//Cache key example: "shop.products:hash({"status":"active"},10,{})"
//Contains: namespace + query parameter hash
Q3: How to clear the cache of a specific collection?
A: You can use the invalidate() method:
const { collection } = await msq.connect();
//Clear all caches for the products collection
await collection('products').invalidate();
console.log('✅ products collection cache cleared');
//Or manually clear all caches
const cache = msq.getCache();
await cache.clear();
console.log('✅ All caches cleared');
For details, see: Caching Policy Document
Q4: Can the configuration of getDefaults() be modified?
A: cannot be modified directly, but can be overwritten during query:
const defaults = msq.getDefaults();
console.log('Default limit:', defaults.findLimit); // 20
//❌ The default configuration cannot be modified
//defaults.findLimit = 50; // invalid
//✅ Override default value when querying
const result = await collection('products').find(
{},
{ limit: 50 } //Override the default 20
);
If you need to modify the global defaults, you should recreate the MonSQLize instance.
Q5: What are the practical uses of getNamespace()?
A: Identification mainly used for logging, debugging and cross-database operations:
const { collection } = await msq.connect();
//Purpose 1: Logging
function logQuery(collectionName, query) {
const namespace = collection(collectionName).getNamespace();
console.log(`[${namespace}] query:`, query);
}
//Purpose 2: Cache key prefix
function getCacheKey(collectionName, query) {
const namespace = collection(collectionName).getNamespace();
return `${namespace}:${JSON.stringify(query)}`;
}
//Purpose 3: Debugging multi-database environments
const shopProducts = collection('products').getNamespace(); // shop.products
const testProducts = collection('products').getNamespace(); // test.products
if (shopProducts !== testProducts) {
console.log('⚠️ Working on different databases');
}
Q6: How to check how many caches a specific collection has? (Recommended method ⭐)
A: The most convenient way is to use getNamespace() + cache.keys():
const { collection } = await msq.connect();
const cache = msq.getCache();
if (cache) {
//Method 1: Use getNamespace() (recommended, more precise)
const ns = collection('products').getNamespace();
const pattern = `*"collection":"${ns.collection}"*"db":"${ns.db}"*`;
const productsKeys = await cache.keys(pattern);
console.log(`Products collection cache quantity: ${productsKeys.length}`);
console.log(`Namespace: ${ns.db}.${ns.collection}`);
//Method 2: Use collection name only (simple but possible cross-database match)
const simpleKeys = await cache.keys('*"collection":"products"*');
console.log(`Simple match: ${simpleKeys.length}`);
//Statistics by operation type (mode using getNamespace)
const findKeys = await cache.keys(`${pattern}*"op":"find"*`);
const countKeys = await cache.keys(`${pattern}*"op":"count"*`);
const findOneKeys = await cache.keys(`${pattern}*"op":"findOne"*`);
console.log('Cache details:', {
Total: productsKeys.length,
find: findKeys.length,
count: countKeys.length,
findOne: findOneKeys.length
});
}
**Why is it recommended to use getNamespace()? **
- ✅ More precise: match both database name and collection name
- ✅ Avoid cross-database matching: collections with the same name in other databases will not be matched
- ✅ Type safety: returns structured namespace object
- ✅ Easy to expand: you can directly obtain
iid, type and other information
Mode Description:
*"collection":"products"*"db":"shop"* - Exact match (recommended)
*"collection":"products"* - simple match (possibly across databases)
*"op":"find"* - matches specific operation types
Q7: How to clear the cache of an operation for a specific collection?
A: Use the invalidate(op) method to specify the operation type:
const { collection } = await msq.connect();
//Only clear the find operation cache for products
await collection('products').invalidate('find');
console.log('✅ products find cache has been cleared');
//count and findOne caches still work
For details, see: Caching Policy Document
References