mongoose-model-class
v3.0.0
Published
Define Mongoose models using ES6/TypeScript classes with lifecycle hooks, static methods, and virtuals
Maintainers
Readme
mongoose-model-class
Define Mongoose models using ES6/TypeScript classes with lifecycle hooks, static methods, instance methods, and virtual properties.
Installation
npm install mongoose-model-class mongoose
# or
pnpm add mongoose-model-class mongooseUsage
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<UserDocument> {
// 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<UserDocument>) {
if (doc.isModified('password')) {
doc.password = await hashPassword(doc.password);
}
}
// Lifecycle hook: after save
async afterSave(doc: HydratedDocument<UserDocument>) {
console.log(`User ${doc.name} saved`);
}
// Lifecycle hook: before delete
async beforeDelete(doc: HydratedDocument<UserDocument>) {
console.log(`Deleting user ${doc.name}`);
}
}
export default User;Building the Model
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: '[email protected]',
password: 'secret123',
});
// Static methods work
const found = await UserModel.findByEmail('[email protected]');
// Instance methods work
console.log(user.getDisplayName()); // 'JOHN DOE'
// Virtuals work
console.log(user.initials); // 'JD'API
Class Methods
| 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 |
Lifecycle Hooks
| 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 |
Static Properties
| Property | Description |
|----------|-------------|
| MongooseModelClass.adapter | Mongoose instance |
| MongooseModelClass.Schema | Schema class |
| MongooseModelClass.types | Schema.Types (ObjectId, etc.) |
| MongooseModelClass.parseObjectId(id) | Parse string to ObjectId |
Migration from v2.x
Breaking Changes
- Node.js 18+ required
- ES Modules - Use
importinstead ofrequire - Mongoose 6+ -
remove()hooks replaced withdeleteOne() - Renamed hooks -
beforeRemove/afterRemove→beforeDelete/afterDelete
Migration Steps
// 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<UserDocument> {
async beforeDelete(doc) {
// cleanup (no need for next())
}
}License
Apache-2.0
