Skip to main content

api-database-mongodb

MongoDB with Mongoose ODM - schemas, models, queries, aggregation, indexes, TypeScript typing, connection management

الانتقال إلى التثبيت

معلومات المصدر

المستودع
majiayu000/claude-skill-registry-data
آخر نشاط في المصدر
٢٣ يونيو ٢٠٢٦ في ١١:٠٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢١
التفرعات
٨

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
2 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
api-database-mongodb
description
MongoDB with Mongoose ODM - schemas, models, queries, aggregation, indexes, TypeScript typing, connection management
# MongoDB / Mongoose Patterns > **Quick Guide:** Use Mongoose as the ODM for MongoDB. Define schemas with automatic TypeScript inference, use `lean()` for read-only queries, prefer embedding over referencing for co-accessed data, place `$match` early in aggregation pipelines, and always define indexes to match your query patterns. --- <critical_requirements> ## CRITICAL: Before Using This Skill > **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants) **(You MUST define Mongoose middleware (pre/post hooks) BEFORE calling `model()` -- hooks registered after model compilation are silently ignored)** **(You MUST pass `{ session }` to EVERY operation inside a transaction -- missing session causes operations to run outside the transaction)** **(You MUST use `.lean()` for read-only queries that send results directly to API responses -- skipping lean wastes 3x memory on hydration overhead)** **(You MUST use `127.0.0.1` instead of `localhost` in connection strings -- Node.js 18+ prefers IPv6 and `localhost` can cause connection timeouts)** **(You MUST NOT use `findOneAndUpdate` / `updateOne` and expect `save` middleware to fire -- only `save()` and `create()` trigger document middleware)** </critical_requirements> --- **Auto-detection:** MongoDB, Mongoose, mongoose.connect, Schema, model, ObjectId, populate, aggregate, $match, $group, $lookup, lean, HydratedDocument, InferSchemaType, MongoClient, Atlas **When to use:** - Defining MongoDB schemas and models with Mongoose - Building CRUD operations and complex queries - Designing aggregation pipelines for analytics and reporting - Managing indexes for query performance - Connecting to MongoDB Atlas or local instances - Modeling document relationships (embedding vs referencing) **Key patterns covered:** - Connection setup (Atlas URI, pooling, error handling) - Schema definition (types, validation, defaults, enums) - Models with TypeScript (automatic inference, methods, statics, virtuals) - CRUD operations (create, find, update, delete, lean) - Query building (filters, projection, sort, limit, populate) **When NOT to use:** - Relational data with complex joins and foreign key constraints (use a relational database) - ACID transactions across many collections as a core pattern (use a relational database) - Simple key-value storage (use a dedicated key-value store) **Detailed Resources:** - For decision frameworks and anti-patterns, see [reference.md](reference.md) **Core Patterns:** - [examples/core.md](examples/core.md) - Connection, schema definition, model creation, TypeScript typing **Query Patterns:** - [examples/queries.md](examples/queries.md) - Complex queries, populate, lean, cursor, pagination **Aggregation:** - [examples/aggregation.md](examples/aggregation.md) - Aggregation pipeline, $match, $group, $lookup, $project **Advanced Patterns:** - [examples/patterns.md](examples/patterns.md) - Schema design (embedding vs referencing), transactions, middleware hooks, virtuals **Indexing:** - [examples/indexes.md](examples/indexes.md) - Index types, compound indexes, text search, geospatial, TTL, performance --- <philosophy> ## Philosophy MongoDB is a document database. Mongoose provides schema-based modeling on top of it. The core principle: **data that is accessed together should be stored together.** **Core principles:** 1. **Schema-first design** -- Define schemas before models. Schemas enforce structure, validation, and defaults at the application layer. 2. **Embed by default** -- Co-accessed data belongs in the same document. Only reference when data is shared across many documents, grows unbounded, or is frequently updated independently. 3. **Lean for reads** -- Use `.lean()` for read-only queries. It returns plain objects (3x less memory) instead of full Mongoose documents. 4. **Index your queries** -- Every query pattern needs a supporting index. Compound indexes follow the Equality-Sort-Range (ESR) rule. 5. **Aggregation over application logic** -- Push data transformation to the database with aggregation pipelines instead of processing in application code. 6. **TypeScript inference** -- Let Mongoose infer types from schema definitions. Avoid manually duplicating interfaces unless you need methods/statics/virtuals. **When to use MongoDB / Mongoose:** - Document-oriented data (user profiles, product catalogs, content) - Flexible schemas that evolve over time - Hierarchical or nested data structures - High read throughput with embedding - Geospatial queries and full-text search **When NOT to use:** - Highly relational data with complex joins (use a relational database) - Strong ACID guarantees across many collections as a primary pattern - Fixed schemas where relational constraints are critical - Time-series data at scale (use a dedicated time-series database) </philosophy> --- <patterns> ## Core Patterns ### Pattern 1: Connection Setup Establish a single connection at application startup. Use environment variables for credentials. ```typescript import mongoose from "mongoose"; const POOL_SIZE_MAX = 10; const POOL_SIZE_MIN = 2; const SERVER_SELECTION_TIMEOUT_MS = 5000; const SOCKET_TIMEOUT_MS = 45000; async function connectDatabase(): Promise<typeof mongoose> { const uri = process.env.MONGODB_URI; if (!uri) { throw new Error("MONGODB_URI environment variable is required"); } const connection = await mongoose.connect(uri, { maxPoolSize: POOL_SIZE_MAX, minPoolSize: POOL_SIZE_MIN, serverSelectionTimeoutMS: SERVER_SELECTION_TIMEOUT_MS, socketTimeoutMS: SOCKET_TIMEOUT_MS, retryWrites: true, retryReads: true, }); return connection; } export { connectDatabase }; ``` **Why good:** Named constants for all numeric values, environment variable for URI, typed return, error on missing URI ```typescript // BAD: Hardcoded URI, no options, no error handling mongoose.connect("mongodb://localhost:27017/mydb"); ``` **Why bad:** Hardcoded connection string leaks credentials, `localhost` fails on Node.js 18+ (IPv6), no pool or timeout configuration, no error handling #### Connection Events ```typescript mongoose.connection.on("connected", () => { console.log("MongoDB connected"); }); mongoose.connection.on("error", (err) => { console.error("MongoDB connection error:", err); }); mongoose.connection.on("disconnected", () => { console.log("MongoDB disconnected"); }); ``` --- ### Pattern 2: Schema Definition with TypeScript Let Mongoose infer types from the schema definition. Use explicit interfaces only when adding methods, statics, or virtuals. #### Automatic Type Inference (Preferred) ```typescript import { Schema, model } from "mongoose"; const userSchema = new Schema( { name: { type: String, required: true, trim: true }, email: { type: String, required: true, unique: true, lowercase: true }, role: { type: String, enum: ["admin", "user", "moderator"] as const, default: "user", }, age: { type: Number, min: 0, max: 150 }, isActive: { type: Boolean, default: true }, tags: [{ type: String }], metadata: { type: Schema.Types.Mixed }, }, { timestamps: true }, ); const User = model("User", userSchema); export { User, userSchema }; ``` **Why good:** TypeScript infers document types from schema, `as const` preserves enum literal types, timestamps added via schema option, named exports #### Explicit Interface (For Methods/Statics/Virtuals) ```typescript import { Schema, model, type HydratedDocument, type Model, type Types, } from "mongoose"; interface IUser { name: string; email: string; role: "admin" | "user" | "moderator"; organizationId: Types.ObjectId; } interface IUserMethods { isAdmin(): boolean; } interface IUserVirtuals { displayName: string; } type UserModel = Model<IUser, {}, IUserMethods, IUserVirtuals>; const userSchema = new Schema< IUser, UserModel, IUserMethods, {}, IUserVirtuals >({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, role: { type: String, enum: ["admin", "user", "moderator"], default: "user" }, organizationId: { type: Schema.Types.ObjectId, ref: "Organization", required: true, }, }); userSchema.methods.isAdmin = function () { return this.role === "admin"; }; userSchema.virtual("displayName").get(function () { return `${this.name} (${this.role})`; }); const User = model<IUser, UserModel>("User", userSchema); export { User, userSchema }; export type { IUser, IUserMethods }; export type UserDocument = HydratedDocument< IUser, IUserMethods & IUserVirtuals >; ``` **Why good:** Separate interfaces for document shape, methods, and virtuals; generic parameters correctly ordered; `HydratedDocument` type exported for consumers ```typescript // BAD: Duplicate interface and schema definition without inference interface IUser { name: string; email: string; } const userSchema = new Schema({ name: String, email: String }); // Types are disconnected -- schema changes don't update the interface ``` **Why bad:** Manual interface duplicates schema definition, interface and schema can drift out of sync, no validation constraints in schema --- ### Pattern 3: CRUD Operations #### Create ```typescript // Single document const user = await User.create({ name: "Alice", email: "alice@example.com", role: "admin", }); // Bulk insert const BATCH_SIZE = 1000; const users = generateUsers(BATCH_SIZE); await User.insertMany(users, { ordered: false }); ``` #### Read with Lean ```typescript // Single document (read-only response) const user = await User.findById(id).lean(); // Multiple with filters const PAGE_SIZE = 20; const activeAdmins = await User.find({ role: "admin", isActive: true }) .select("name email role") .sort({ name: 1 }) .limit(PAGE_SIZE) .lean(); ``` **Why good:** `.lean()` for read-only responses, `.select()` for projection, named constant for page size #### Update ```typescript // Update with save() -- triggers middleware const user = await User.findById(id); if (!user) { throw new Error(`User not found: ${id}`); } user.name = "Updated Name"; await user.save(); // Direct update -- does NOT trigger save middleware await User.findByIdAndUpdate( id, { $set: { name: "Updated" } }, { new: true, runValidators: true }, ); // Bulk update await User.updateMany( { isActive: false }, { $set: { archivedAt: new Date() } }, ); ``` **Why good:** `save()` triggers middleware, `findByIdAndUpdate` with `runValidators: true` enforces schema validation, `{ new: true }` returns updated document #### Delete ```typescript await User.findByIdAndDelete(id); await User.deleteMany({ isActive: false, archivedAt: { $lt: cutoffDate } }); ``` ```typescript // BAD: No null check before calling method on potentially null result const user = await User.findById(id); user.deleteOne(); // TypeError if user is null ``` **Why bad:** No null check before calling method on potentially null result, crashes at runtime if document not found --- ### Pattern 4: Query Building #### Filters and Operators ```typescript const MIN_AGE = 18; const MAX_AGE = 65; // Comparison operators const users = await User.find({ age: { $gte: MIN_AGE, $lte: MAX_AGE }, role: { $in: ["admin", "moderator"] }, email: { $regex: /@company\.com$/i }, }).lean(); // Logical operators const results = await User.find({ $or: [{ role: "admin" }, { isActive: true, age: { $gte: MIN_AGE } }], }).lean(); ``` #### Populate (Reference Resolution) ```typescript const post = await Post.findById(id) .populate("author", "name email") // select specific fields .populate({ path: "comments", populate: { path: "author", select: "name" }, // nested populate options: { sort: { createdAt: -1 }, limit: 10 }, }) .lean(); ``` **Why good:** Field selection on populate reduces data transfer, nested populate for deep references, sort and limit on populated array ```typescript // BAD: Populating everything without field selection const post = await Post.findById(id) .populate("author") // returns ALL author fields .populate("comments"); // returns ALL comments, unbounded ``` **Why bad:** No field selection wastes bandwidth and memory, unbounded populate can return thousands of documents, each populate is a separate database query --- ### Pattern 5: Schema Validation ```typescript const productSchema = new Schema({ name: { type: String,
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub