Global configuration and best practices
Global Configuration and Best Practices
Mongoose's global configuration allows developers to uniformly manage connection behaviors, model definitions, and query logic. Proper use of these configurations can significantly improve code maintainability and avoid repetitive settings. Below, we elaborate on core configuration items and their application scenarios, covering connection settings, model options, and plugin mechanisms.
Connection Pooling and Performance Tuning
Connection pool configuration directly impacts database operation throughput. By default, Mongoose creates 5 connections. High-concurrency scenarios require adjustments:
mongoose.connect('mongodb://localhost:27017/mydb', {
poolSize: 20, // Maximum connections
socketTimeoutMS: 45000, // Socket timeout
connectTimeoutMS: 30000, // Connection timeout
serverSelectionTimeoutMS: 5000 // Server selection timeout
});
Key parameters:
maxPoolSize
: Replaces the legacypoolSize
parameter. Recommended to set to 1-2 times the number of application threads.waitQueueTimeoutMS
: Maximum wait time for connection requests in the queue.heartbeatFrequencyMS
: Heartbeat detection interval (default: 10 seconds).
For production environments, retry mechanisms are recommended:
const options = {
autoIndex: false, // Disable auto-indexing in production
retryWrites: true,
retryReads: true,
retryAttempts: 3,
retryDelay: 1000
};
Schema-Level Configuration
Schema definitions can preset model behaviors to avoid repetitive declarations in each query:
const userSchema = new mongoose.Schema({
username: String,
email: String
}, {
timestamps: true, // Automatically add createdAt/updatedAt
minimize: false, // Preserve empty objects
toJSON: {
virtuals: true,
transform: (doc, ret) => {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
return ret;
}
},
optimisticConcurrency: true // Enable optimistic locking
});
Notable configuration items:
strictQuery
: Controls field filtering during queries (recommended:true
).id
: Whether to map_id
toid
(default:true
).versionKey
: Modify or disable the__v
version control field.
Global Plugin Registration
Global plugins can uniformly extend all model functionalities. Typical use cases include automatically updating timestamps:
mongoose.plugin((schema) => {
schema.pre('save', function(next) {
this.updatedAt = new Date();
next();
});
schema.post('find', function(docs) {
console.log(`Query returned ${docs.length} records`);
});
});
Common plugin combinations in real-world projects:
mongoose-autopopulate
: Auto-populate referenced fields.mongoose-lean-virtuals
: Add virtual fields to lean queries.mongoose-paginate-v2
: Pagination plugin.
// Pagination plugin example
mongoose.plugin(require('mongoose-paginate-v2'), {
limit: 10,
customLabels: {
totalDocs: 'itemCount',
docs: 'itemsList'
}
});
Query Middleware Optimization
Global query hooks enable AOP-style logic reuse:
mongoose.set('debug', process.env.NODE_ENV === 'development');
// Add base filtering to all queries
mongoose.plugin((schema) => {
schema.pre(/^find/, function() {
if (!this.getFilter().isDeleted) {
this.where({ isDeleted: false });
}
});
});
// Auto-convert ID queries
mongoose.plugin((schema) => {
schema.pre('find', function() {
const { _id } = this.getQuery();
if (_id && typeof _id === 'string') {
this.where({ _id: new mongoose.Types.ObjectId(_id) });
}
});
});
Multi-Tenancy Strategies
In SaaS applications, global configurations simplify tenant isolation:
// Dynamic database connections
const tenantConnections = {};
function getTenantConnection(tenantId) {
if (!tenantConnections[tenantId]) {
tenantConnections[tenantId] = mongoose.createConnection(
`mongodb://localhost/${tenantId}`,
{ useNewUrlParser: true }
);
}
return tenantConnections[tenantId];
}
// Model registration middleware
mongoose.plugin((schema) => {
schema.statics.byTenant = function(tenantId) {
const conn = getTenantConnection(tenantId);
return conn.model(this.modelName, this.schema);
};
});
// Usage example
const Product = mongoose.model('Product', productSchema);
const tenantAProducts = Product.byTenant('tenantA').find();
Performance Monitoring Integration
Integrate monitoring tools via global configurations:
const statsDClient = require('hot-shots');
mongoose.plugin((schema) => {
const metrics = new statsDClient();
schema.post('save', function(doc) {
metrics.increment('mongoose.save_operations');
});
schema.post('find', function(docs) {
metrics.timing('mongoose.query_time', this._mongooseOptions.executionTime);
});
});
Combine with APM tools for granular monitoring:
const apm = require('elastic-apm-node');
mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {
const span = apm.startSpan(`MongoDB ${collectionName}.${methodName}`);
// ...Execution logic
span?.end();
});
Type Conversion and Validation
Customize global type handling:
// Custom Decimal128 conversion
mongoose.Schema.Types.Decimal128.set('toJSON', {
transform: (val) => val ? parseFloat(val.toString()) : null
});
// Global validator
mongoose.plugin((schema) => {
schema.pre('validate', function(next) {
if (this.email && !/.+@.+\..+/.test(this.email)) {
this.invalidate('email', 'Invalid email format');
}
next();
});
});
// Enhanced enum types
mongoose.Schema.Types.String.set('validate', {
validator: function(val) {
if (this.enumValues && !this.enumValues.includes(val)) {
return false;
}
return true;
},
message: props => `${props.value} is not a valid enum value`
});
Multilingual Support Solutions
Implement model multilingualism via global plugins:
mongoose.plugin((schema) => {
const languages = ['en', 'zh', 'ja'];
languages.forEach(lang => {
schema.add({
[`name_${lang}`]: String,
[`description_${lang}`]: String
});
});
schema.methods.getLocalized = function(field, lang = 'en') {
return this[`${field}_${lang}`] || this[field];
};
});
// Usage example
const productSchema = new mongoose.Schema({ baseName: String });
const Product = mongoose.model('Product', productSchema);
const p = new Product({
baseName: 'Default',
name_zh: '默认名称',
name_ja: 'デフォルト'
});
console.log(p.getLocalized('name', 'zh')); // Output: 默认名称
Caching Strategy Implementation
Global query caching example:
const cache = new Map();
mongoose.plugin((schema) => {
schema.statics.cachedFind = async function(query, ttl = 60) {
const key = JSON.stringify({
model: this.modelName,
query
});
if (cache.has(key)) {
return cache.get(key);
}
const result = await this.find(query);
cache.set(key, result);
setTimeout(() => cache.delete(key), ttl * 1000);
return result;
};
});
// Usage example
const User = mongoose.model('User');
const users = await User.cachedFind({ active: true }, 300);
Security Measures
Global security-related configurations:
// Prevent query injection
mongoose.set('sanitizeFilter', true);
mongoose.set('sanitizeProjection', true);
// Field-level encryption
const encryptedFields = require('mongoose-encrypted-field');
mongoose.plugin(encryptedFields, {
secret: process.env.ENCRYPTION_KEY,
fields: ['creditCard', 'ssn']
});
// Audit logging
mongoose.plugin((schema) => {
schema.add({
createdBy: mongoose.Schema.Types.ObjectId,
updatedBy: mongoose.Schema.Types.ObjectId
});
schema.pre('save', function() {
if (this.isNew) {
this.createdBy = currentUser;
}
this.updatedBy = currentUser;
});
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:多数据库连接管理
下一篇:Schema的定义与结构