install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/mongoose" ~/.claude/skills/comeonoliver-skillshub-mongoose && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/mongoose/SKILL.mdsource content
Mongoose — MongoDB ODM for Node.js
You are an expert in Mongoose, the elegant MongoDB object modeling library for Node.js. You help developers define schemas with validation, build queries with a fluent API, use middleware hooks, populate references, create virtual fields, and handle transactions — providing structure and type safety on top of MongoDB's flexible document model.
Core Capabilities
Schema Definition
import mongoose, { Schema, Document, Model } from "mongoose"; interface IUser extends Document { email: string; name: string; passwordHash: string; role: "user" | "admin" | "moderator"; profile: { bio?: string; avatar?: string; website?: string }; posts: mongoose.Types.ObjectId[]; createdAt: Date; updatedAt: Date; fullName: string; } const userSchema = new Schema<IUser>( { email: { type: String, required: [true, "Email is required"], unique: true, lowercase: true, trim: true, match: [/^\S+@\S+\.\S+$/, "Invalid email format"], }, name: { type: String, required: true, minlength: 2, maxlength: 100 }, passwordHash: { type: String, required: true, select: false }, role: { type: String, enum: ["user", "admin", "moderator"], default: "user" }, profile: { bio: { type: String, maxlength: 500 }, avatar: String, website: { type: String, match: /^https?:\/\// }, }, posts: [{ type: Schema.Types.ObjectId, ref: "Post" }], }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true }, }, ); // Virtual field userSchema.virtual("fullName").get(function () { return this.name; }); // Index for search userSchema.index({ email: 1 }); userSchema.index({ name: "text", "profile.bio": "text" }); // Pre-save middleware userSchema.pre("save", async function (next) { if (this.isModified("passwordHash")) { this.passwordHash = await bcrypt.hash(this.passwordHash, 12); } next(); }); // Static method userSchema.statics.findByEmail = function (email: string) { return this.findOne({ email: email.toLowerCase() }); }; // Instance method userSchema.methods.verifyPassword = async function (password: string) { return bcrypt.compare(password, this.passwordHash); }; const User: Model<IUser> = mongoose.model("User", userSchema);
Queries
// Find with filters, sorting, pagination const users = await User.find({ role: "user" }) .sort({ createdAt: -1 }) .skip(20).limit(10) .select("name email profile.avatar") .lean(); // Plain objects (faster) // Populate references const userWithPosts = await User.findById(id) .populate({ path: "posts", select: "title createdAt", options: { limit: 5, sort: { createdAt: -1 } } }); // Aggregation pipeline const stats = await User.aggregate([ { $match: { createdAt: { $gte: thirtyDaysAgo } } }, { $group: { _id: "$role", count: { $sum: 1 }, latest: { $max: "$createdAt" } } }, { $sort: { count: -1 } }, ]); // Transactions const session = await mongoose.startSession(); await session.withTransaction(async () => { const user = await User.create([{ name: "Alice", email: "alice@example.com", passwordHash: "..." }], { session }); await Post.create([{ title: "First Post", author: user[0]._id }], { session }); });
Installation
npm install mongoose
Best Practices
- Schema validation — Define strict schemas; use
,required
,enum
,match
validatorsmin/max - Lean queries — Use
for read-only queries; returns plain objects, 5x faster than Mongoose documents.lean() - Indexes — Add indexes for fields you query/sort by; use
to verify query plansexplain() - Population — Use
sparingly; for complex joins, prefer aggregationpopulate()$lookup - Middleware — Use
for hashing, validation;pre('save')
for notifications, loggingpost('save') - Timestamps — Enable
; auto-managestimestamps: true
andcreatedAtupdatedAt - Transactions — Use sessions for multi-document operations; requires replica set or MongoDB Atlas
- TypeScript — Define interfaces extending
; use generics withDocument
for full type safetySchema<IUser>