autoworkflow 3.1.5 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +26 -0
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/post-edit.sh +190 -17
  12. package/.claude/hooks/pre-edit.sh +221 -0
  13. package/.claude/hooks/session-check.sh +90 -0
  14. package/.claude/settings.json +56 -6
  15. package/.claude/settings.local.json +5 -1
  16. package/.claude/skills/actix.md +337 -0
  17. package/.claude/skills/alembic.md +504 -0
  18. package/.claude/skills/angular.md +237 -0
  19. package/.claude/skills/api-design.md +187 -0
  20. package/.claude/skills/aspnet-core.md +377 -0
  21. package/.claude/skills/astro.md +245 -0
  22. package/.claude/skills/auth-clerk.md +327 -0
  23. package/.claude/skills/auth-firebase.md +367 -0
  24. package/.claude/skills/auth-nextauth.md +359 -0
  25. package/.claude/skills/auth-supabase.md +368 -0
  26. package/.claude/skills/axum.md +386 -0
  27. package/.claude/skills/blazor.md +456 -0
  28. package/.claude/skills/chi.md +348 -0
  29. package/.claude/skills/code-review.md +133 -0
  30. package/.claude/skills/csharp.md +296 -0
  31. package/.claude/skills/css-modules.md +325 -0
  32. package/.claude/skills/cypress.md +343 -0
  33. package/.claude/skills/debugging.md +133 -0
  34. package/.claude/skills/diesel.md +392 -0
  35. package/.claude/skills/django.md +301 -0
  36. package/.claude/skills/docker.md +319 -0
  37. package/.claude/skills/doctrine.md +473 -0
  38. package/.claude/skills/documentation.md +182 -0
  39. package/.claude/skills/dotnet.md +409 -0
  40. package/.claude/skills/drizzle.md +293 -0
  41. package/.claude/skills/echo.md +321 -0
  42. package/.claude/skills/eloquent.md +256 -0
  43. package/.claude/skills/emotion.md +426 -0
  44. package/.claude/skills/entity-framework.md +370 -0
  45. package/.claude/skills/express.md +316 -0
  46. package/.claude/skills/fastapi.md +329 -0
  47. package/.claude/skills/fastify.md +299 -0
  48. package/.claude/skills/fiber.md +315 -0
  49. package/.claude/skills/flask.md +322 -0
  50. package/.claude/skills/gin.md +342 -0
  51. package/.claude/skills/git.md +116 -0
  52. package/.claude/skills/github-actions.md +353 -0
  53. package/.claude/skills/go.md +377 -0
  54. package/.claude/skills/gorm.md +409 -0
  55. package/.claude/skills/graphql.md +478 -0
  56. package/.claude/skills/hibernate.md +379 -0
  57. package/.claude/skills/hono.md +306 -0
  58. package/.claude/skills/java.md +400 -0
  59. package/.claude/skills/jest.md +313 -0
  60. package/.claude/skills/jpa.md +282 -0
  61. package/.claude/skills/kotlin.md +347 -0
  62. package/.claude/skills/kubernetes.md +363 -0
  63. package/.claude/skills/laravel.md +414 -0
  64. package/.claude/skills/mcp-browser.md +320 -0
  65. package/.claude/skills/mcp-database.md +219 -0
  66. package/.claude/skills/mcp-fetch.md +241 -0
  67. package/.claude/skills/mcp-filesystem.md +204 -0
  68. package/.claude/skills/mcp-github.md +217 -0
  69. package/.claude/skills/mcp-memory.md +240 -0
  70. package/.claude/skills/mcp-search.md +218 -0
  71. package/.claude/skills/mcp-slack.md +262 -0
  72. package/.claude/skills/micronaut.md +388 -0
  73. package/.claude/skills/mongodb.md +319 -0
  74. package/.claude/skills/mongoose.md +355 -0
  75. package/.claude/skills/mysql.md +281 -0
  76. package/.claude/skills/nestjs.md +335 -0
  77. package/.claude/skills/nextjs-app-router.md +260 -0
  78. package/.claude/skills/nextjs-pages.md +172 -0
  79. package/.claude/skills/nuxt.md +202 -0
  80. package/.claude/skills/openapi.md +489 -0
  81. package/.claude/skills/performance.md +199 -0
  82. package/.claude/skills/php.md +398 -0
  83. package/.claude/skills/playwright.md +371 -0
  84. package/.claude/skills/postgresql.md +257 -0
  85. package/.claude/skills/prisma.md +293 -0
  86. package/.claude/skills/pydantic.md +304 -0
  87. package/.claude/skills/pytest.md +313 -0
  88. package/.claude/skills/python.md +272 -0
  89. package/.claude/skills/quarkus.md +377 -0
  90. package/.claude/skills/react.md +230 -0
  91. package/.claude/skills/redis.md +391 -0
  92. package/.claude/skills/refactoring.md +143 -0
  93. package/.claude/skills/remix.md +246 -0
  94. package/.claude/skills/rest-api.md +490 -0
  95. package/.claude/skills/rocket.md +366 -0
  96. package/.claude/skills/rust.md +341 -0
  97. package/.claude/skills/sass.md +380 -0
  98. package/.claude/skills/sea-orm.md +382 -0
  99. package/.claude/skills/security.md +167 -0
  100. package/.claude/skills/sequelize.md +395 -0
  101. package/.claude/skills/spring-boot.md +416 -0
  102. package/.claude/skills/sqlalchemy.md +269 -0
  103. package/.claude/skills/sqlx-rust.md +408 -0
  104. package/.claude/skills/state-jotai.md +346 -0
  105. package/.claude/skills/state-mobx.md +353 -0
  106. package/.claude/skills/state-pinia.md +431 -0
  107. package/.claude/skills/state-redux.md +337 -0
  108. package/.claude/skills/state-tanstack-query.md +434 -0
  109. package/.claude/skills/state-zustand.md +340 -0
  110. package/.claude/skills/styled-components.md +403 -0
  111. package/.claude/skills/svelte.md +238 -0
  112. package/.claude/skills/sveltekit.md +207 -0
  113. package/.claude/skills/symfony.md +437 -0
  114. package/.claude/skills/tailwind.md +279 -0
  115. package/.claude/skills/terraform.md +394 -0
  116. package/.claude/skills/testing-library.md +371 -0
  117. package/.claude/skills/trpc.md +426 -0
  118. package/.claude/skills/typeorm.md +368 -0
  119. package/.claude/skills/vitest.md +330 -0
  120. package/.claude/skills/vue.md +202 -0
  121. package/.claude/skills/warp.md +365 -0
  122. package/README.md +163 -52
  123. package/package.json +1 -1
  124. package/system/triggers.md +256 -17
@@ -0,0 +1,319 @@
1
+ # MongoDB Skill
2
+
3
+ ## Schema Design Patterns
4
+ \`\`\`javascript
5
+ // Embedding (denormalization) - for data accessed together
6
+ {
7
+ _id: ObjectId("..."),
8
+ title: "Blog Post",
9
+ content: "...",
10
+ author: {
11
+ _id: ObjectId("..."),
12
+ name: "John Doe",
13
+ email: "john@example.com"
14
+ },
15
+ comments: [
16
+ { user: "Jane", text: "Great post!", date: ISODate("...") },
17
+ { user: "Bob", text: "Thanks!", date: ISODate("...") }
18
+ ]
19
+ }
20
+
21
+ // Referencing (normalization) - for unbounded or frequently updated data
22
+ {
23
+ _id: ObjectId("..."),
24
+ title: "Blog Post",
25
+ content: "...",
26
+ authorId: ObjectId("..."), // Reference to users collection
27
+ commentIds: [ObjectId("..."), ObjectId("...")] // Bounded array
28
+ }
29
+
30
+ // Bucket pattern - for time series data
31
+ {
32
+ sensorId: "sensor_001",
33
+ date: ISODate("2024-01-15"),
34
+ readings: [
35
+ { time: ISODate("2024-01-15T00:00:00Z"), value: 23.5 },
36
+ { time: ISODate("2024-01-15T00:01:00Z"), value: 23.6 },
37
+ // ... up to 1440 readings per day
38
+ ],
39
+ count: 1440
40
+ }
41
+
42
+ // Polymorphic pattern - for different item types
43
+ {
44
+ _id: ObjectId("..."),
45
+ itemType: "book",
46
+ title: "MongoDB Guide",
47
+ author: "Jane Doe",
48
+ isbn: "978-..."
49
+ }
50
+ {
51
+ _id: ObjectId("..."),
52
+ itemType: "movie",
53
+ title: "The Matrix",
54
+ director: "Wachowskis",
55
+ runtime: 136
56
+ }
57
+ \`\`\`
58
+
59
+ ## Indexes
60
+ \`\`\`javascript
61
+ // Single field index
62
+ db.users.createIndex({ email: 1 }) // 1 = ascending, -1 = descending
63
+
64
+ // Unique index
65
+ db.users.createIndex({ email: 1 }, { unique: true })
66
+
67
+ // Compound index (order matters for queries!)
68
+ db.posts.createIndex({ authorId: 1, createdAt: -1 })
69
+
70
+ // Partial index (smaller, more efficient)
71
+ db.users.createIndex(
72
+ { email: 1 },
73
+ { partialFilterExpression: { status: "active" } }
74
+ )
75
+
76
+ // TTL index (auto-expire documents)
77
+ db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
78
+
79
+ // Text index for full-text search
80
+ db.posts.createIndex({ title: "text", content: "text" })
81
+
82
+ // Wildcard index (flexible schema)
83
+ db.products.createIndex({ "attributes.$**": 1 })
84
+
85
+ // Geospatial index
86
+ db.locations.createIndex({ coordinates: "2dsphere" })
87
+
88
+ // Check index usage
89
+ db.users.aggregate([{ $indexStats: {} }])
90
+ \`\`\`
91
+
92
+ ## CRUD Operations
93
+ \`\`\`javascript
94
+ // Insert
95
+ db.users.insertOne({ email: "user@example.com", name: "John" })
96
+ db.users.insertMany([
97
+ { email: "user1@example.com", name: "User 1" },
98
+ { email: "user2@example.com", name: "User 2" }
99
+ ])
100
+
101
+ // Find
102
+ db.users.findOne({ email: "user@example.com" })
103
+ db.users.find({ status: "active" }).limit(20).skip(0).sort({ createdAt: -1 })
104
+
105
+ // Projection (select fields)
106
+ db.users.find({ status: "active" }, { email: 1, name: 1, _id: 0 })
107
+
108
+ // Update
109
+ db.users.updateOne(
110
+ { _id: ObjectId("...") },
111
+ { $set: { name: "Jane", updatedAt: new Date() } }
112
+ )
113
+
114
+ // Upsert
115
+ db.users.updateOne(
116
+ { email: "user@example.com" },
117
+ { $set: { name: "John" }, $setOnInsert: { createdAt: new Date() } },
118
+ { upsert: true }
119
+ )
120
+
121
+ // Update operators
122
+ db.posts.updateOne({ _id }, {
123
+ $set: { title: "New Title" },
124
+ $inc: { views: 1 },
125
+ $push: { tags: "mongodb" },
126
+ $addToSet: { likes: userId }, // Only add if not exists
127
+ $pull: { dislikes: userId }, // Remove from array
128
+ $currentDate: { updatedAt: true }
129
+ })
130
+
131
+ // Delete
132
+ db.users.deleteOne({ _id: ObjectId("...") })
133
+ db.users.deleteMany({ status: "inactive", lastLogin: { $lt: oneYearAgo } })
134
+ \`\`\`
135
+
136
+ ## Query Operators
137
+ \`\`\`javascript
138
+ // Comparison
139
+ db.users.find({ age: { $gt: 18, $lte: 65 } })
140
+ db.posts.find({ status: { $in: ["published", "featured"] } })
141
+ db.users.find({ deletedAt: { $exists: false } })
142
+
143
+ // Logical
144
+ db.users.find({
145
+ $and: [
146
+ { status: "active" },
147
+ { $or: [
148
+ { role: "admin" },
149
+ { email: { $regex: /@company\\.com$/ } }
150
+ ]}
151
+ ]
152
+ })
153
+
154
+ // Array queries
155
+ db.posts.find({ tags: "mongodb" }) // Array contains
156
+ db.posts.find({ tags: { $all: ["mongodb", "database"] } }) // Contains all
157
+ db.posts.find({ "tags.0": "featured" }) // First element
158
+ db.posts.find({ tags: { $size: 3 } }) // Exact array length
159
+ db.posts.find({ comments: { $elemMatch: { user: "John", score: { $gte: 5 } } } })
160
+
161
+ // Text search
162
+ db.posts.find({ $text: { $search: "mongodb tutorial" } })
163
+ .sort({ score: { $meta: "textScore" } })
164
+ \`\`\`
165
+
166
+ ## Aggregation Pipeline
167
+ \`\`\`javascript
168
+ // Basic aggregation
169
+ db.orders.aggregate([
170
+ { $match: { status: "completed" } },
171
+ { $group: {
172
+ _id: "$customerId",
173
+ totalSpent: { $sum: "$total" },
174
+ orderCount: { $sum: 1 },
175
+ avgOrder: { $avg: "$total" }
176
+ }},
177
+ { $sort: { totalSpent: -1 } },
178
+ { $limit: 10 }
179
+ ])
180
+
181
+ // Lookup (join)
182
+ db.posts.aggregate([
183
+ { $match: { published: true } },
184
+ { $lookup: {
185
+ from: "users",
186
+ localField: "authorId",
187
+ foreignField: "_id",
188
+ as: "author"
189
+ }},
190
+ { $unwind: "$author" }, // Convert array to object
191
+ { $project: {
192
+ title: 1,
193
+ "author.name": 1,
194
+ "author.email": 1
195
+ }}
196
+ ])
197
+
198
+ // Faceted search (multiple aggregations)
199
+ db.products.aggregate([
200
+ { $match: { status: "active" } },
201
+ { $facet: {
202
+ results: [
203
+ { $sort: { createdAt: -1 } },
204
+ { $skip: 0 },
205
+ { $limit: 20 }
206
+ ],
207
+ totalCount: [
208
+ { $count: "count" }
209
+ ],
210
+ categories: [
211
+ { $group: { _id: "$category", count: { $sum: 1 } } }
212
+ ],
213
+ priceRange: [
214
+ { $group: {
215
+ _id: null,
216
+ min: { $min: "$price" },
217
+ max: { $max: "$price" }
218
+ }}
219
+ ]
220
+ }}
221
+ ])
222
+
223
+ // Unwind arrays
224
+ db.posts.aggregate([
225
+ { $unwind: "$tags" },
226
+ { $group: { _id: "$tags", count: { $sum: 1 } } },
227
+ { $sort: { count: -1 } }
228
+ ])
229
+
230
+ // Date operations
231
+ db.orders.aggregate([
232
+ { $group: {
233
+ _id: {
234
+ year: { $year: "$createdAt" },
235
+ month: { $month: "$createdAt" }
236
+ },
237
+ revenue: { $sum: "$total" }
238
+ }},
239
+ { $sort: { "_id.year": 1, "_id.month": 1 } }
240
+ ])
241
+ \`\`\`
242
+
243
+ ## Transactions (Replica Set required)
244
+ \`\`\`javascript
245
+ const session = client.startSession();
246
+
247
+ try {
248
+ session.startTransaction();
249
+
250
+ await users.insertOne({ email, name }, { session });
251
+ await posts.insertOne({ title, authorId: userId }, { session });
252
+
253
+ await session.commitTransaction();
254
+ } catch (error) {
255
+ await session.abortTransaction();
256
+ throw error;
257
+ } finally {
258
+ session.endSession();
259
+ }
260
+
261
+ // With callback (auto-retry)
262
+ await session.withTransaction(async () => {
263
+ await users.updateOne({ _id: senderId }, { $inc: { balance: -100 } }, { session });
264
+ await users.updateOne({ _id: receiverId }, { $inc: { balance: 100 } }, { session });
265
+ });
266
+ \`\`\`
267
+
268
+ ## Change Streams
269
+ \`\`\`javascript
270
+ // Watch for changes (real-time)
271
+ const changeStream = db.collection('users').watch([
272
+ { $match: { operationType: { $in: ['insert', 'update'] } } }
273
+ ]);
274
+
275
+ changeStream.on('change', (change) => {
276
+ console.log('Change detected:', change.operationType);
277
+ console.log('Document:', change.fullDocument);
278
+ });
279
+
280
+ // Resume after failure
281
+ const resumeToken = change._id;
282
+ const resumedStream = collection.watch([], { resumeAfter: resumeToken });
283
+ \`\`\`
284
+
285
+ ## Performance & Monitoring
286
+ \`\`\`javascript
287
+ // Explain query plan
288
+ db.users.find({ email: "test@example.com" }).explain("executionStats")
289
+
290
+ // Index recommendations
291
+ db.users.aggregate([{ $indexStats: {} }])
292
+
293
+ // Current operations
294
+ db.currentOp({ "active": true })
295
+
296
+ // Server status
297
+ db.serverStatus()
298
+
299
+ // Collection stats
300
+ db.users.stats()
301
+ \`\`\`
302
+
303
+ ## ❌ DON'T
304
+ - Store unbounded arrays (use bucketing or references)
305
+ - Create too many indexes (write overhead)
306
+ - Use \`$where\` or JavaScript execution in queries
307
+ - Skip index for frequently queried fields
308
+ - Embed frequently changing data
309
+ - Use find() without limits on large collections
310
+
311
+ ## ✅ DO
312
+ - Design schema for query patterns
313
+ - Use compound indexes matching query shapes
314
+ - Use aggregation pipeline for complex queries
315
+ - Use change streams for real-time updates
316
+ - Set appropriate read/write concerns
317
+ - Use TTL indexes for expiring data
318
+ - Monitor index usage and slow queries
319
+ - Use projection to limit returned fields
@@ -0,0 +1,355 @@
1
+ # Mongoose Skill
2
+
3
+ ## Connection Setup
4
+ \`\`\`typescript
5
+ import mongoose from 'mongoose';
6
+
7
+ // Connection with options
8
+ await mongoose.connect(process.env.MONGODB_URI!, {
9
+ maxPoolSize: 10,
10
+ serverSelectionTimeoutMS: 5000,
11
+ socketTimeoutMS: 45000,
12
+ });
13
+
14
+ // Connection events
15
+ mongoose.connection.on('connected', () => console.log('MongoDB connected'));
16
+ mongoose.connection.on('error', (err) => console.error('MongoDB error:', err));
17
+ mongoose.connection.on('disconnected', () => console.log('MongoDB disconnected'));
18
+
19
+ // Graceful shutdown
20
+ process.on('SIGINT', async () => {
21
+ await mongoose.connection.close();
22
+ process.exit(0);
23
+ });
24
+ \`\`\`
25
+
26
+ ## Schema Definition with TypeScript
27
+ \`\`\`typescript
28
+ import { Schema, model, Document, Types, Model } from 'mongoose';
29
+
30
+ // TypeScript interfaces
31
+ interface IUser {
32
+ email: string;
33
+ name: string;
34
+ password: string;
35
+ role: 'user' | 'admin';
36
+ settings: Record<string, unknown>;
37
+ posts: Types.ObjectId[];
38
+ createdAt: Date;
39
+ updatedAt: Date;
40
+ }
41
+
42
+ // Methods interface
43
+ interface IUserMethods {
44
+ comparePassword(candidate: string): Promise<boolean>;
45
+ generateAuthToken(): string;
46
+ }
47
+
48
+ // Static methods interface
49
+ interface UserModel extends Model<IUser, {}, IUserMethods> {
50
+ findByEmail(email: string): Promise<IUser | null>;
51
+ }
52
+
53
+ // Schema definition
54
+ const userSchema = new Schema<IUser, UserModel, IUserMethods>({
55
+ email: {
56
+ type: String,
57
+ required: [true, 'Email is required'],
58
+ unique: true,
59
+ lowercase: true,
60
+ trim: true,
61
+ validate: {
62
+ validator: (v: string) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(v),
63
+ message: 'Invalid email format',
64
+ },
65
+ },
66
+ name: {
67
+ type: String,
68
+ required: true,
69
+ trim: true,
70
+ minlength: [2, 'Name must be at least 2 characters'],
71
+ maxlength: [100, 'Name cannot exceed 100 characters'],
72
+ },
73
+ password: {
74
+ type: String,
75
+ required: true,
76
+ select: false, // Excluded from queries by default
77
+ },
78
+ role: {
79
+ type: String,
80
+ enum: ['user', 'admin'],
81
+ default: 'user',
82
+ },
83
+ settings: {
84
+ type: Schema.Types.Mixed,
85
+ default: {},
86
+ },
87
+ posts: [{
88
+ type: Schema.Types.ObjectId,
89
+ ref: 'Post',
90
+ }],
91
+ }, {
92
+ timestamps: true, // Adds createdAt, updatedAt
93
+ toJSON: { virtuals: true },
94
+ toObject: { virtuals: true },
95
+ });
96
+
97
+ // Indexes
98
+ userSchema.index({ email: 1 });
99
+ userSchema.index({ role: 1, createdAt: -1 });
100
+
101
+ export const User = model<IUser, UserModel>('User', userSchema);
102
+ \`\`\`
103
+
104
+ ## Virtuals
105
+ \`\`\`typescript
106
+ // Virtual property (not stored in DB)
107
+ userSchema.virtual('fullName').get(function() {
108
+ return \`\${this.firstName} \${this.lastName}\`;
109
+ });
110
+
111
+ // Virtual populate (referenced documents)
112
+ userSchema.virtual('postCount', {
113
+ ref: 'Post',
114
+ localField: '_id',
115
+ foreignField: 'author',
116
+ count: true,
117
+ });
118
+
119
+ // Usage
120
+ const user = await User.findById(id).populate('postCount');
121
+ console.log(user.postCount); // Number of posts
122
+ \`\`\`
123
+
124
+ ## Instance & Static Methods
125
+ \`\`\`typescript
126
+ // Instance method
127
+ userSchema.methods.comparePassword = async function(candidate: string): Promise<boolean> {
128
+ return bcrypt.compare(candidate, this.password);
129
+ };
130
+
131
+ userSchema.methods.generateAuthToken = function(): string {
132
+ return jwt.sign({ id: this._id, role: this.role }, process.env.JWT_SECRET!);
133
+ };
134
+
135
+ // Static method
136
+ userSchema.statics.findByEmail = function(email: string) {
137
+ return this.findOne({ email: email.toLowerCase() });
138
+ };
139
+
140
+ // Usage
141
+ const user = await User.findByEmail('test@example.com'); // Static
142
+ const isValid = await user.comparePassword('password123'); // Instance
143
+ const token = user.generateAuthToken(); // Instance
144
+ \`\`\`
145
+
146
+ ## Middleware (Hooks)
147
+ \`\`\`typescript
148
+ // Pre-save hook (hash password)
149
+ userSchema.pre('save', async function(next) {
150
+ if (!this.isModified('password')) return next();
151
+ this.password = await bcrypt.hash(this.password, 12);
152
+ next();
153
+ });
154
+
155
+ // Pre-find hook (exclude deleted)
156
+ userSchema.pre(/^find/, function(next) {
157
+ // 'this' is the query
158
+ this.where({ deletedAt: { $exists: false } });
159
+ next();
160
+ });
161
+
162
+ // Post-save hook
163
+ userSchema.post('save', function(doc) {
164
+ console.log('User saved:', doc._id);
165
+ // Send welcome email, log audit, etc.
166
+ });
167
+
168
+ // Pre-remove hook (cascade delete)
169
+ userSchema.pre('deleteOne', { document: true }, async function() {
170
+ await Post.deleteMany({ author: this._id });
171
+ });
172
+ \`\`\`
173
+
174
+ ## Query Patterns
175
+ \`\`\`typescript
176
+ // Find operations
177
+ const user = await User.findById(id);
178
+ const user = await User.findOne({ email });
179
+ const users = await User.find({ role: 'user' });
180
+
181
+ // With population (joins)
182
+ const user = await User.findById(id)
183
+ .populate('posts')
184
+ .populate({
185
+ path: 'posts',
186
+ match: { published: true },
187
+ select: 'title createdAt',
188
+ options: { sort: { createdAt: -1 }, limit: 10 },
189
+ });
190
+
191
+ // Select specific fields
192
+ const user = await User.findById(id).select('email name role');
193
+ const user = await User.findById(id).select('-password -settings'); // Exclude
194
+
195
+ // Include normally excluded field
196
+ const user = await User.findById(id).select('+password');
197
+
198
+ // Lean queries (plain JS objects, faster)
199
+ const user = await User.findById(id).lean();
200
+
201
+ // Pagination
202
+ const page = 1;
203
+ const limit = 20;
204
+ const users = await User.find({ role: 'user' })
205
+ .sort({ createdAt: -1 })
206
+ .skip((page - 1) * limit)
207
+ .limit(limit)
208
+ .lean();
209
+
210
+ const total = await User.countDocuments({ role: 'user' });
211
+
212
+ // Complex queries
213
+ const users = await User.find({
214
+ $and: [
215
+ { role: 'user' },
216
+ { createdAt: { $gte: new Date('2024-01-01') } },
217
+ { $or: [
218
+ { email: { $regex: '@company.com$' } },
219
+ { name: { $regex: /^admin/i } },
220
+ ]},
221
+ ],
222
+ });
223
+ \`\`\`
224
+
225
+ ## Aggregation Pipeline
226
+ \`\`\`typescript
227
+ // Basic aggregation
228
+ const stats = await User.aggregate([
229
+ { $match: { role: 'user' } },
230
+ { $group: {
231
+ _id: '$status',
232
+ count: { $sum: 1 },
233
+ avgAge: { $avg: '$age' },
234
+ }},
235
+ { $sort: { count: -1 } },
236
+ ]);
237
+
238
+ // With lookup (join)
239
+ const usersWithPosts = await User.aggregate([
240
+ { $match: { role: 'user' } },
241
+ { $lookup: {
242
+ from: 'posts',
243
+ localField: '_id',
244
+ foreignField: 'author',
245
+ as: 'posts',
246
+ pipeline: [
247
+ { $match: { published: true } },
248
+ { $sort: { createdAt: -1 } },
249
+ { $limit: 5 },
250
+ ],
251
+ }},
252
+ { $addFields: { postCount: { $size: '$posts' } } },
253
+ { $project: { password: 0 } },
254
+ ]);
255
+
256
+ // Pagination with facet
257
+ const result = await User.aggregate([
258
+ { $match: { role: 'user' } },
259
+ { $facet: {
260
+ data: [
261
+ { $sort: { createdAt: -1 } },
262
+ { $skip: (page - 1) * limit },
263
+ { $limit: limit },
264
+ ],
265
+ meta: [
266
+ { $count: 'total' },
267
+ ],
268
+ }},
269
+ ]);
270
+ \`\`\`
271
+
272
+ ## Transactions
273
+ \`\`\`typescript
274
+ const session = await mongoose.startSession();
275
+
276
+ try {
277
+ session.startTransaction();
278
+
279
+ const user = await User.create([{ email, name }], { session });
280
+
281
+ await Post.create([{
282
+ title: 'Welcome Post',
283
+ author: user[0]._id,
284
+ }], { session });
285
+
286
+ await session.commitTransaction();
287
+ } catch (error) {
288
+ await session.abortTransaction();
289
+ throw error;
290
+ } finally {
291
+ session.endSession();
292
+ }
293
+
294
+ // With withTransaction helper
295
+ await session.withTransaction(async () => {
296
+ await User.create([userData], { session });
297
+ await Post.create([postData], { session });
298
+ });
299
+ \`\`\`
300
+
301
+ ## Validation
302
+ \`\`\`typescript
303
+ const productSchema = new Schema({
304
+ price: {
305
+ type: Number,
306
+ required: true,
307
+ min: [0, 'Price cannot be negative'],
308
+ validate: {
309
+ validator: Number.isFinite,
310
+ message: 'Price must be a finite number',
311
+ },
312
+ },
313
+ category: {
314
+ type: String,
315
+ enum: {
316
+ values: ['electronics', 'clothing', 'food'],
317
+ message: '{VALUE} is not a valid category',
318
+ },
319
+ },
320
+ tags: {
321
+ type: [String],
322
+ validate: {
323
+ validator: (v: string[]) => v.length <= 10,
324
+ message: 'Cannot have more than 10 tags',
325
+ },
326
+ },
327
+ });
328
+
329
+ // Custom async validator
330
+ userSchema.path('email').validate({
331
+ validator: async function(email: string) {
332
+ const count = await User.countDocuments({ email, _id: { $ne: this._id } });
333
+ return count === 0;
334
+ },
335
+ message: 'Email already exists',
336
+ });
337
+ \`\`\`
338
+
339
+ ## ❌ DON'T
340
+ - Store unbounded arrays in documents (use references)
341
+ - Forget to create indexes for query patterns
342
+ - Use \`find()\` without limits on large collections
343
+ - Nest populations deeply (performance killer)
344
+ - Use \`new Model()\` + \`save()\` when \`create()\` works
345
+ - Skip \`.lean()\` when you don't need Mongoose features
346
+
347
+ ## ✅ DO
348
+ - Design schemas around query patterns
349
+ - Use \`lean()\` for read-only operations
350
+ - Create compound indexes for common queries
351
+ - Use aggregation for complex data transformations
352
+ - Use transactions for multi-document operations
353
+ - Validate data at schema level
354
+ - Use virtuals for computed properties
355
+ - Set \`select: false\` for sensitive fields