乐闻世界logo
搜索文章和话题

What are the best practices for Mongoose performance optimization?

2月22日 20:12

Mongoose performance optimization is key to developing efficient applications. Through proper configuration and best practices, you can significantly improve query speed and overall performance.

Connection Optimization

Connection Pool Configuration

javascript
mongoose.connect('mongodb://localhost:27017/mydb', { maxPoolSize: 100, // Maximum connections minPoolSize: 10, // Minimum connections socketTimeoutMS: 45000, // Socket timeout serverSelectionTimeoutMS: 5000, // Server selection timeout connectTimeoutMS: 10000 // Connection timeout });

Connection Reuse

javascript
// Establish connection when application starts mongoose.connect('mongodb://localhost:27017/mydb'); // Don't frequently close and reconnect // Avoid creating new connections on every request

Index Optimization

Creating Indexes

javascript
const userSchema = new Schema({ email: { type: String, index: true, // Single field index unique: true }, name: { type: String, index: true }, age: Number, status: String }); // Compound index userSchema.index({ status: 1, age: -1 }); // Text index userSchema.index({ name: 'text', bio: 'text' }); // Geospatial index userSchema.index({ location: '2dsphere' });

Index Strategy

  1. Create indexes for frequently queried fields
  2. Use compound indexes to optimize multi-field queries
  3. Avoid too many indexes affecting write performance
  4. Regularly analyze query performance and optimize indexes
javascript
// Analyze query plan const query = User.find({ email: 'john@example.com' }); const explanation = await query.explain('executionStats'); console.log(explanation.executionStats);

Query Optimization

Use lean()

javascript
// Return plain JavaScript objects, better performance const users = await User.find().lean(); // Use lean() for read-only queries const users = await User.find({ status: 'active' }).lean();

Selective Querying

javascript
// Only query needed fields const users = await User.find() .select('name email age') .lean(); // Exclude large fields const users = await User.find() .select('-largeField -anotherLargeField');

Limit Result Count

javascript
// Use limit to restrict returned count const users = await User.find() .limit(100); // Implement pagination const page = 1; const pageSize = 20; const users = await User.find() .skip((page - 1) * pageSize) .limit(pageSize);

Use Projection

javascript
// Projection reduces data transfer const users = await User.find( { status: 'active' }, { name: 1, email: 1, _id: 0 } );

Batch Operations

Batch Insert

javascript
// Use insertMany instead of multiple insertOne const users = await User.insertMany([ { name: 'John', email: 'john@example.com' }, { name: 'Jane', email: 'jane@example.com' }, // ... more users ]);

Batch Update

javascript
// Use updateMany instead of multiple updateOne await User.updateMany( { status: 'pending' }, { status: 'active' } );

Batch Delete

javascript
// Use deleteMany instead of multiple deleteOne await User.deleteMany({ status: 'deleted' });

Caching Strategy

Query Caching

javascript
const userSchema = new Schema({ name: String, email: String }, { query: { cache: true } }); // Enable caching const users = await User.find().cache(); // Set cache time const users = await User.find().cache(60); // 60 seconds

Application Layer Caching

javascript
const NodeCache = require('node-cache'); const cache = new NodeCache({ stdTTL: 600 }); // 10 minute cache async function getUserById(userId) { const cacheKey = `user:${userId}`; let user = cache.get(cacheKey); if (!user) { user = await User.findById(userId).lean(); if (user) { cache.set(cacheKey, user); } } return user; }

Data Model Optimization

Embedding vs Reference

javascript
// Embedding for one-to-one or one-to-many, small child documents const userSchema = new Schema({ name: String, profile: { bio: String, avatar: String } }); // Reference for one-to-many or many-to-many, large child documents const postSchema = new Schema({ title: String, author: { type: Schema.Types.ObjectId, ref: 'User' } });

Avoid Deep Nesting

javascript
// Avoid overly deep nested structures // Not recommended const badSchema = new Schema({ level1: { level2: { level3: { level4: { data: String } } } } }); // Recommended: Flatten structure const goodSchema = new Schema({ level1: String, level2: String, level3: String, level4: String });

Monitoring and Tuning

Query Performance Monitoring

javascript
// Enable debug mode mongoose.set('debug', true); // Custom debug function mongoose.set('debug', (collectionName, method, query, doc) => { console.log(`${collectionName}.${method}`, JSON.stringify(query)); });

Slow Query Logging

javascript
// Log slow queries mongoose.connection.on('connected', () => { mongoose.connection.db.admin().command({ profile: 1, slowms: 100 // Queries over 100ms }); });

Best Practices Summary

  1. Connection Management: Use connection pools, avoid frequent connect/disconnect
  2. Index Optimization: Create appropriate indexes for frequently queried fields
  3. Query Optimization: Use lean(), selective queries, limit results
  4. Batch Operations: Use batch operations instead of multiple single operations
  5. Caching Strategy: Reasonably use query cache and application layer cache
  6. Data Model: Choose embedding or reference based on access patterns
  7. Monitoring and Tuning: Continuously monitor query performance and optimize timely
  8. Avoid N+1 Queries: Design data structure properly, avoid loop queries
标签:Mongoose