阿里云主机折上折
  • 微信号
Current Site:Index > Global configuration and best practices

Global configuration and best practices

Author:Chuan Chen 阅读数:42310人阅读 分类: MongoDB

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 legacy poolSize 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 to id (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:

  1. mongoose-autopopulate: Auto-populate referenced fields.
  2. mongoose-lean-virtuals: Add virtual fields to lean queries.
  3. 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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.