Define Mongoose models using ES6/TypeScript classes with lifecycle hooks, static methods, and virtuals
npm install mongoose-model-classDefine Mongoose models using ES6/TypeScript classes with lifecycle hooks, static methods, instance methods, and virtual properties.
``bash`
npm install mongoose-model-class mongooseor
pnpm add mongoose-model-class mongoose
`typescript
import { MongooseModelClass } from 'mongoose-model-class';
import type { Document, HydratedDocument } from 'mongoose';
interface UserDocument extends Document {
name: string;
email: string;
password: string;
createdAt: Date;
}
class User extends MongooseModelClass
// Required: Define your schema
schema() {
return {
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
};
}
// Optional: Schema options
options() {
return { timestamps: true };
}
// Optional: Configure schema (add indexes, plugins, etc.)
config(schema) {
schema.index({ email: 1 });
}
// Instance method
getDisplayName() {
return this.name.toUpperCase();
}
// Static method
static async findByEmail(email: string) {
return this.findOne({ email });
}
// Virtual property (getter)
get initials() {
return this.name.split(' ').map(n => n[0]).join('');
}
// Lifecycle hook: before save
async beforeSave(doc: HydratedDocument
if (doc.isModified('password')) {
doc.password = await hashPassword(doc.password);
}
}
// Lifecycle hook: after save
async afterSave(doc: HydratedDocument
console.log(User ${doc.name} saved);
}
// Lifecycle hook: before delete
async beforeDelete(doc: HydratedDocument
console.log(Deleting user ${doc.name});
}
}
export default User;
`
`typescript
import mongoose from 'mongoose';
import User from './models/User';
const connection = await mongoose.createConnection('mongodb://localhost/mydb');
const userModel = new User();
const UserModel = userModel.build(connection, 'User');
// Now use it like a regular Mongoose model
const user = await UserModel.create({
name: 'John Doe',
email: 'john@example.com',
password: 'secret123',
});
// Static methods work
const found = await UserModel.findByEmail('john@example.com');
// Instance methods work
console.log(user.getDisplayName()); // 'JOHN DOE'
// Virtuals work
console.log(user.initials); // 'JD'
`
| Method | Description |
|--------|-------------|
| schema() | Required. Returns schema definition object |options()
| | Returns schema options (timestamps, etc.) |config(schema)
| | Configure schema after creation |build(connection, name)
| | Build and return mongoose model |
| Hook | Description |
|------|-------------|
| beforeSave(doc) | Called before document is saved |afterSave(doc)
| | Called after document is saved |beforeDelete(doc)
| | Called before document is deleted |afterDelete(doc)
| | Called after document is deleted |
| Property | Description |
|----------|-------------|
| MongooseModelClass.adapter | Mongoose instance |MongooseModelClass.Schema
| | Schema class |MongooseModelClass.types
| | Schema.Types (ObjectId, etc.) |MongooseModelClass.parseObjectId(id)
| | Parse string to ObjectId |
1. Node.js 18+ required
2. ES Modules - Use import instead of requireremove()
3. Mongoose 6+ - hooks replaced with deleteOne()beforeRemove
4. Renamed hooks - /afterRemove → beforeDelete/afterDelete
`javascript
// Before (v2.x)
const MongooseModelClass = require('mongoose-model-class');
class User extends MongooseModelClass {
beforeRemove(doc, next) {
// cleanup
next();
}
}
// After (v3.x)
import { MongooseModelClass } from 'mongoose-model-class';
class User extends MongooseModelClass
async beforeDelete(doc) {
// cleanup (no need for next())
}
}
``
Apache-2.0