Developing with MongoDB
Quick Start
// Schema with Mongoose
import mongoose, { Schema, Document } from 'mongoose';
interface IUser extends Document {
email: string;
profile: { firstName: string; lastName: string };
createdAt: Date;
}
const userSchema = new Schema<IUser>({
email: { type: String, required: true, unique: true, lowercase: true },
profile: {
firstName: { type: String, required: true },
lastName: { type: String, required: true },
},
}, { timestamps: true });
userSchema.index({ email: 1 });
export const User = mongoose.model<IUser>('User', userSchema);
Features
| Feature |
Description |
Guide |
| Document Schema |
Type-safe schema design with Mongoose |
Embed related data, use references for large collections |
| CRUD Operations |
Create, read, update, delete with type safety |
Use findById, findOne, updateOne, deleteOne |
| Aggregation Pipelines |
Complex data transformations and analytics |
Chain $match, $group, $lookup, $project stages |
| Indexing |
Query optimization with proper indexes |
Create compound indexes matching query patterns |
| Transactions |
Multi-document ACID operations |
Use sessions for operations requiring atomicity |
| Change Streams |
Real-time data change notifications |
Watch collections for inserts, updates, deletes |
Common Patterns
Repository Pattern with Pagination
async findPaginated(filter: FilterQuery<IUser>, page = 1, limit = 20) {
const [data, total] = await Promise.all([
User.find(filter).sort({ createdAt: -1 }).skip((page - 1) * limit).limit(limit),
User.countDocuments(filter),
]);
return { data, pagination: { page, limit, total, totalPages: Math.ceil(total / limit) } };
}
Aggregation Pipeline
const stats = await Order.aggregate([
{ $match: { status: 'completed', createdAt: { $gte: startDate } } },
{ $group: { _id: '$userId', total: { $sum: '$amount' }, count: { $sum: 1 } } },
{ $sort: { total: -1 } },
{ $limit: 10 },
]);
Transaction for Order Creation
const session = await mongoose.startSession();
try {
session.startTransaction();
await Product.updateOne({ _id: productId }, { $inc: { stock: -quantity } }, { session });
const order = await Order.create([{ userId, items, total }], { session });
await session.commitTransaction();
return order[0];
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
Best Practices
| Do |
Avoid |
| Design schemas based on query patterns |
Embedding large arrays in documents |
| Create indexes for frequently queried fields |
Using $where or mapReduce in production |
Use lean() for read-only queries |
Skipping validation on writes |
| Implement pagination for large datasets |
Storing large files directly (use GridFS) |
| Set connection pool size appropriately |
Hardcoding connection strings |
| Use transactions for multi-document ops |
Ignoring index usage in explain plans |
| Add TTL indexes for expiring data |
Creating too many indexes (write overhead) |
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: developing-with-mongodb3description: Use when working with the agent implements MongoDB NoSQL database solutions with document modeling, aggregation pipelines, and Mongoose ODM. Use when building document-based applications, designing schemas, writing aggregations, or implementing NoSQL patterns.4---56# Developing with MongoDB78## Quick Start910```typescript11// Schema with Mongoose12import mongoose, { Schema, Document } from 'mongoose';1314interface IUser extends Document {15 email: string;16 profile: { firstName: string; lastName: string };17 createdAt: Date;18}1920const userSchema = new Schema<IUser>({21 email: { type: String, required: true, unique: true, lowercase: true },22 profile: {23 firstName: { type: String, required: true },24 lastName: { type: String, required: true },25 },26}, { timestamps: true });2728userSchema.index({ email: 1 });29export const User = mongoose.model<IUser>('User', userSchema);30```3132## Features3334| Feature | Description | Guide |35|---------|-------------|-------|36| Document Schema | Type-safe schema design with Mongoose | Embed related data, use references for large collections |37| CRUD Operations | Create, read, update, delete with type safety | Use `findById`, `findOne`, `updateOne`, `deleteOne` |38| Aggregation Pipelines | Complex data transformations and analytics | Chain `$match`, `$group`, `$lookup`, `$project` stages |39| Indexing | Query optimization with proper indexes | Create compound indexes matching query patterns |40| Transactions | Multi-document ACID operations | Use sessions for operations requiring atomicity |41| Change Streams | Real-time data change notifications | Watch collections for inserts, updates, deletes |4243## Common Patterns4445### Repository Pattern with Pagination4647```typescript48async findPaginated(filter: FilterQuery<IUser>, page = 1, limit = 20) {49 const [data, total] = await Promise.all([50 User.find(filter).sort({ createdAt: -1 }).skip((page - 1) * limit).limit(limit),51 User.countDocuments(filter),52 ]);53 return { data, pagination: { page, limit, total, totalPages: Math.ceil(total / limit) } };54}55```5657### Aggregation Pipeline5859```typescript60const stats = await Order.aggregate([61 { $match: { status: 'completed', createdAt: { $gte: startDate } } },62 { $group: { _id: '$userId', total: { $sum: '$amount' }, count: { $sum: 1 } } },63 { $sort: { total: -1 } },64 { $limit: 10 },65]);66```6768### Transaction for Order Creation6970```typescript71const session = await mongoose.startSession();72try {73 session.startTransaction();74 await Product.updateOne({ _id: productId }, { $inc: { stock: -quantity } }, { session });75 const order = await Order.create([{ userId, items, total }], { session });76 await session.commitTransaction();77 return order[0];78} catch (error) {79 await session.abortTransaction();80 throw error;81} finally {82 session.endSession();83}84```8586## Best Practices8788| Do | Avoid |89|----|-------|90| Design schemas based on query patterns | Embedding large arrays in documents |91| Create indexes for frequently queried fields | Using `$where` or mapReduce in production |92| Use `lean()` for read-only queries | Skipping validation on writes |93| Implement pagination for large datasets | Storing large files directly (use GridFS) |94| Set connection pool size appropriately | Hardcoding connection strings |95| Use transactions for multi-document ops | Ignoring index usage in explain plans |96| Add TTL indexes for expiring data | Creating too many indexes (write overhead) |9798---99> Converted and distributed by [TomeVault](https://tomevault.io/claim/doanchienthangdev) — claim your Tome and manage your conversions.100<!-- tomevault:4.0:skill_md:2026-04-13 -->