Loading...
Loading...
Guide for Mongoose ODM (2025-2026 Edition), covering Mongoose 8.x/9.x, TypeScript integration, and performance best practices.
npx skill4agent add toilahuongg/shopify-agents-kit mongoose@types/mongooseasync/awaitLengthyDocumentDocumentimport { Types } from 'mongoose';
export interface IUser {
name: string;
email: string;
role: 'admin' | 'user';
tags: string[];
organization?: Types.ObjectId; // Use specific type for ObjectIds
createdAt?: Date;
}import mongoose, { Schema, model } from 'mongoose';
import { IUser } from './interfaces';
const userSchema = new Schema<IUser>({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
role: { type: String, enum: ['admin', 'user'], default: 'user' },
tags: [String],
organization: { type: Schema.Types.ObjectId, ref: 'Organization' }
}, {
timestamps: true /* Automatically manages createdAt/updatedAt */
});
// ⚡ 2025 Best Practice: Avoid "extends Document" on the interface.
// Let 'model<IUser>' handle the HydratedDocument type automatically.
export const User = mongoose.models.User || model<IUser>('User', userSchema);// 'user' is typed as HydratedDocument<IUser> automatically
const user = await User.findOne({ email: 'test@example.com' });
if (user) {
console.log(user.name); // Typed string
await user.save(); // Typed method
}.lean().lean()// Returns plain JS object (IUser), NOT a Mongoose document
const users = await User.find({ role: 'admin' }).lean(); // Schema definition
userSchema.index({ organization: 1, email: 1 }); // Optimized lookupconst names = await User.find({}, { name: 1 }).lean();import mongoose from 'mongoose';
const MONGODB_URI = process.env.MONGODB_URI!;
if (!MONGODB_URI) {
throw new Error('Please define the MONGODB_URI environment variable');
}
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = (global as any).mongoose;
if (!cached) {
cached = (global as any).mongoose = { conn: null, promise: null };
}
async function connectDb() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose;
});
}
try {
cached.conn = await cached.promise;
} catch (e) {
cached.promise = null;
throw e;
}
return cached.conn;
}
export default connectDb;