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

What are the differences between Mongoose instance methods and static methods?

2月22日 20:12

Mongoose provides instance methods and static methods as two ways to extend model functionality. Understanding the differences and use cases of these two methods is crucial for writing maintainable code.

Instance Methods

Instance methods are added to document instances and can be called on individual documents. These methods can access the this keyword to reference the current document.

Defining Instance Methods

javascript
const userSchema = new Schema({ firstName: String, lastName: String, email: String, password: String, createdAt: { type: Date, default: Date.now } }); // Add instance method userSchema.methods.getFullName = function() { return `${this.firstName} ${this.lastName}`; }; userSchema.methods.isNewUser = function() { const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); return this.createdAt > oneDayAgo; }; userSchema.methods.comparePassword = function(candidatePassword) { // Use bcrypt to compare passwords return bcrypt.compare(candidatePassword, this.password); }; const User = mongoose.model('User', userSchema); // Use instance method const user = await User.findById(userId); console.log(user.getFullName()); // "John Doe" console.log(user.isNewUser()); // true/false const isMatch = await user.comparePassword('password123');

Instance Method Use Cases

  1. Document-specific operations: Perform operations on single documents
  2. Data validation: Validate document data
  3. Data transformation: Convert document data formats
  4. Business logic: Encapsulate business logic
  5. Status checking: Check document status
javascript
// Example: Order instance methods const orderSchema = new Schema({ items: [{ product: { type: Schema.Types.ObjectId, ref: 'Product' }, quantity: Number, price: Number }], status: { type: String, enum: ['pending', 'paid', 'shipped', 'delivered', 'cancelled'] }, createdAt: { type: Date, default: Date.now } }); orderSchema.methods.getTotalPrice = function() { return this.items.reduce((sum, item) => { return sum + (item.price * item.quantity); }, 0); }; orderSchema.methods.canBeCancelled = function() { return ['pending', 'paid'].includes(this.status); }; orderSchema.methods.markAsShipped = function() { if (this.status !== 'paid') { throw new Error('Order must be paid before shipping'); } this.status = 'shipped'; return this.save(); };

Static Methods

Static methods are added to the model class and can be called directly on the model without instantiating documents. These methods are typically used for queries or batch operations.

Defining Static Methods

javascript
// Add static method userSchema.statics.findByEmail = function(email) { return this.findOne({ email }); }; userSchema.statics.getActiveUsers = function() { return this.find({ status: 'active' }); }; userSchema.statics.countByStatus = function(status) { return this.countDocuments({ status }); }; userSchema.statics.findAdultUsers = function() { return this.find({ age: { $gte: 18 } }); }; // Use static method const user = await User.findByEmail('john@example.com'); const activeUsers = await User.getActiveUsers(); const activeCount = await User.countByStatus('active'); const adultUsers = await User.findAdultUsers();

Static Method Use Cases

  1. Query operations: Encapsulate common queries
  2. Batch operations: Execute batch updates or deletions
  3. Statistical operations: Calculate statistical data
  4. Business rules: Implement business rule queries
  5. Complex queries: Encapsulate complex query logic
javascript
// Example: Product static methods const productSchema = new Schema({ name: String, price: Number, category: String, stock: Number, active: { type: Boolean, default: true } }); productSchema.statics.findByCategory = function(category) { return this.find({ category, active: true }); }; productSchema.statics.findInPriceRange = function(min, max) { return this.find({ price: { $gte: min, $lte: max }, active: true }); }; productSchema.statics.findLowStock = function(threshold = 10) { return this.find({ stock: { $lte: threshold }, active: true }); }; productSchema.statics.updateStock = function(productId, quantity) { return this.findByIdAndUpdate( productId, { $inc: { stock: quantity } }, { new: true } ); };

Instance Methods vs Static Methods

Comparison

FeatureInstance MethodsStatic Methods
Call methoddocument.method()Model.method()
Access thisCan access document instanceCannot access document instance
Use casesSingle document operationsQueries and batch operations
Definition locationschema.methodsschema.statics
Return valueUsually returns document or modified valueUsually returns query results

Selection Guide

Use instance methods when:

  • Need to operate on a single document
  • Need to access document properties
  • Method is related to a specific document
  • Need to modify document state

Use static methods when:

  • Need to query multiple documents
  • Need to perform batch operations
  • Method is related to document collection
  • Don't need to access a specific document

Advanced Usage

Async Methods

javascript
// Async instance method userSchema.methods.sendWelcomeEmail = async function() { const emailService = require('./services/email'); await emailService.send({ to: this.email, subject: 'Welcome!', body: `Hello ${this.firstName}!` }); return this; }; // Async static method userSchema.statics.sendNewsletter = async function(subject, content) { const users = await this.find({ subscribed: true }); const emailService = require('./services/email'); for (const user of users) { await emailService.send({ to: user.email, subject, body: content }); } return users.length; };

Chaining

javascript
// Static method returns query builder userSchema.statics.queryActive = function() { return this.find({ active: true }); }; // Use chaining const users = await User.queryActive() .select('name email') .sort({ name: 1 }) .limit(10);

Combined Usage

javascript
// Static method queries, instance method processes const users = await User.findByEmail('john@example.com'); if (user) { await user.sendWelcomeEmail(); }

Best Practices

  1. Clear naming: Use descriptive method names
  2. Single responsibility: Each method should do one thing
  3. Error handling: Handle error situations properly
  4. Documentation: Add clear comments for methods
  5. Type safety: Use TypeScript or JSDoc
  6. Test coverage: Write tests for custom methods
  7. Avoid duplication: Don't duplicate existing Mongoose methods
  8. Performance considerations: Be aware of method performance impact
标签:Mongoose