omgkit 2.1.0 → 2.2.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 (56) hide show
  1. package/package.json +1 -1
  2. package/plugin/skills/SKILL_STANDARDS.md +743 -0
  3. package/plugin/skills/databases/mongodb/SKILL.md +797 -28
  4. package/plugin/skills/databases/postgresql/SKILL.md +494 -18
  5. package/plugin/skills/databases/prisma/SKILL.md +776 -30
  6. package/plugin/skills/databases/redis/SKILL.md +885 -25
  7. package/plugin/skills/devops/aws/SKILL.md +686 -28
  8. package/plugin/skills/devops/docker/SKILL.md +466 -18
  9. package/plugin/skills/devops/github-actions/SKILL.md +684 -29
  10. package/plugin/skills/devops/kubernetes/SKILL.md +621 -24
  11. package/plugin/skills/frameworks/django/SKILL.md +920 -20
  12. package/plugin/skills/frameworks/express/SKILL.md +1361 -35
  13. package/plugin/skills/frameworks/fastapi/SKILL.md +1260 -33
  14. package/plugin/skills/frameworks/laravel/SKILL.md +1244 -31
  15. package/plugin/skills/frameworks/nestjs/SKILL.md +1005 -26
  16. package/plugin/skills/frameworks/nextjs/SKILL.md +407 -44
  17. package/plugin/skills/frameworks/rails/SKILL.md +594 -28
  18. package/plugin/skills/frameworks/react/SKILL.md +1006 -32
  19. package/plugin/skills/frameworks/spring/SKILL.md +528 -35
  20. package/plugin/skills/frameworks/vue/SKILL.md +1296 -27
  21. package/plugin/skills/frontend/accessibility/SKILL.md +1108 -34
  22. package/plugin/skills/frontend/frontend-design/SKILL.md +1304 -26
  23. package/plugin/skills/frontend/responsive/SKILL.md +847 -21
  24. package/plugin/skills/frontend/shadcn-ui/SKILL.md +976 -38
  25. package/plugin/skills/frontend/tailwindcss/SKILL.md +831 -35
  26. package/plugin/skills/frontend/threejs/SKILL.md +1298 -29
  27. package/plugin/skills/languages/javascript/SKILL.md +935 -31
  28. package/plugin/skills/languages/python/SKILL.md +489 -25
  29. package/plugin/skills/languages/typescript/SKILL.md +379 -30
  30. package/plugin/skills/methodology/brainstorming/SKILL.md +597 -23
  31. package/plugin/skills/methodology/defense-in-depth/SKILL.md +832 -34
  32. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +665 -31
  33. package/plugin/skills/methodology/executing-plans/SKILL.md +556 -24
  34. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +595 -25
  35. package/plugin/skills/methodology/problem-solving/SKILL.md +429 -61
  36. package/plugin/skills/methodology/receiving-code-review/SKILL.md +536 -24
  37. package/plugin/skills/methodology/requesting-code-review/SKILL.md +632 -21
  38. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +641 -30
  39. package/plugin/skills/methodology/sequential-thinking/SKILL.md +262 -3
  40. package/plugin/skills/methodology/systematic-debugging/SKILL.md +571 -32
  41. package/plugin/skills/methodology/test-driven-development/SKILL.md +779 -24
  42. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +691 -29
  43. package/plugin/skills/methodology/token-optimization/SKILL.md +598 -29
  44. package/plugin/skills/methodology/verification-before-completion/SKILL.md +543 -22
  45. package/plugin/skills/methodology/writing-plans/SKILL.md +590 -18
  46. package/plugin/skills/omega/omega-architecture/SKILL.md +838 -39
  47. package/plugin/skills/omega/omega-coding/SKILL.md +636 -39
  48. package/plugin/skills/omega/omega-sprint/SKILL.md +855 -48
  49. package/plugin/skills/omega/omega-testing/SKILL.md +940 -41
  50. package/plugin/skills/omega/omega-thinking/SKILL.md +703 -50
  51. package/plugin/skills/security/better-auth/SKILL.md +1065 -28
  52. package/plugin/skills/security/oauth/SKILL.md +968 -31
  53. package/plugin/skills/security/owasp/SKILL.md +894 -33
  54. package/plugin/skills/testing/playwright/SKILL.md +764 -38
  55. package/plugin/skills/testing/pytest/SKILL.md +873 -36
  56. package/plugin/skills/testing/vitest/SKILL.md +980 -35
@@ -1,43 +1,812 @@
1
1
  ---
2
2
  name: mongodb
3
- description: MongoDB database. Use for document storage, aggregation, NoSQL.
3
+ description: MongoDB NoSQL database with document modeling, aggregation pipelines, indexing, and Mongoose ODM
4
+ category: databases
5
+ triggers:
6
+ - mongodb
7
+ - mongo
8
+ - mongoose
9
+ - nosql
10
+ - document database
11
+ - bson
12
+ - aggregation
4
13
  ---
5
14
 
6
- # MongoDB Skill
15
+ # MongoDB
7
16
 
8
- ## Document Design
9
- ```javascript
10
- {
11
- _id: ObjectId(),
12
- email: "user@example.com",
17
+ Enterprise-grade **MongoDB NoSQL database** development following industry best practices. This skill covers document modeling, CRUD operations, aggregation pipelines, indexing strategies, Mongoose ODM, transactions, and production-ready patterns used by top engineering teams.
18
+
19
+ ## Purpose
20
+
21
+ Build scalable document-based applications:
22
+
23
+ - Design effective document schemas
24
+ - Implement efficient CRUD operations
25
+ - Write powerful aggregation pipelines
26
+ - Optimize queries with proper indexing
27
+ - Use Mongoose ODM for type safety
28
+ - Handle transactions for data integrity
29
+ - Implement production patterns
30
+
31
+ ## Features
32
+
33
+ ### 1. Document Schema Design
34
+
35
+ ```typescript
36
+ // src/models/user.model.ts
37
+ import mongoose, { Schema, Document, Model } from 'mongoose';
38
+
39
+ // TypeScript interfaces
40
+ export interface IAddress {
41
+ street: string;
42
+ city: string;
43
+ state: string;
44
+ zipCode: string;
45
+ country: string;
46
+ }
47
+
48
+ export interface IUser extends Document {
49
+ email: string;
50
+ password: string;
51
+ profile: {
52
+ firstName: string;
53
+ lastName: string;
54
+ avatar?: string;
55
+ bio?: string;
56
+ };
57
+ addresses: IAddress[];
58
+ role: 'admin' | 'user' | 'guest';
59
+ isActive: boolean;
60
+ lastLoginAt?: Date;
61
+ createdAt: Date;
62
+ updatedAt: Date;
63
+
64
+ // Instance methods
65
+ comparePassword(password: string): Promise<boolean>;
66
+ getFullName(): string;
67
+ }
68
+
69
+ // Statics interface
70
+ export interface IUserModel extends Model<IUser> {
71
+ findByEmail(email: string): Promise<IUser | null>;
72
+ findActiveUsers(): Promise<IUser[]>;
73
+ }
74
+
75
+ // Schema definition
76
+ const addressSchema = new Schema<IAddress>({
77
+ street: { type: String, required: true },
78
+ city: { type: String, required: true },
79
+ state: { type: String, required: true },
80
+ zipCode: { type: String, required: true },
81
+ country: { type: String, required: true, default: 'US' },
82
+ }, { _id: false });
83
+
84
+ const userSchema = new Schema<IUser, IUserModel>({
85
+ email: {
86
+ type: String,
87
+ required: [true, 'Email is required'],
88
+ unique: true,
89
+ lowercase: true,
90
+ trim: true,
91
+ validate: {
92
+ validator: (v: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v),
93
+ message: 'Invalid email format',
94
+ },
95
+ },
96
+ password: {
97
+ type: String,
98
+ required: true,
99
+ minlength: [8, 'Password must be at least 8 characters'],
100
+ select: false, // Don't include in queries by default
101
+ },
13
102
  profile: {
14
- name: "John",
15
- avatar: "url"
103
+ firstName: { type: String, required: true, trim: true },
104
+ lastName: { type: String, required: true, trim: true },
105
+ avatar: String,
106
+ bio: { type: String, maxlength: 500 },
107
+ },
108
+ addresses: [addressSchema],
109
+ role: {
110
+ type: String,
111
+ enum: ['admin', 'user', 'guest'],
112
+ default: 'user',
16
113
  },
17
- createdAt: ISODate()
114
+ isActive: { type: Boolean, default: true },
115
+ lastLoginAt: Date,
116
+ }, {
117
+ timestamps: true,
118
+ toJSON: {
119
+ virtuals: true,
120
+ transform: (doc, ret) => {
121
+ delete ret.password;
122
+ delete ret.__v;
123
+ return ret;
124
+ },
125
+ },
126
+ });
127
+
128
+ // Indexes
129
+ userSchema.index({ email: 1 });
130
+ userSchema.index({ 'profile.firstName': 1, 'profile.lastName': 1 });
131
+ userSchema.index({ role: 1, isActive: 1 });
132
+ userSchema.index({ createdAt: -1 });
133
+
134
+ // Virtual properties
135
+ userSchema.virtual('fullName').get(function() {
136
+ return `${this.profile.firstName} ${this.profile.lastName}`;
137
+ });
138
+
139
+ // Instance methods
140
+ userSchema.methods.comparePassword = async function(password: string): Promise<boolean> {
141
+ const bcrypt = await import('bcrypt');
142
+ return bcrypt.compare(password, this.password);
143
+ };
144
+
145
+ userSchema.methods.getFullName = function(): string {
146
+ return `${this.profile.firstName} ${this.profile.lastName}`;
147
+ };
148
+
149
+ // Static methods
150
+ userSchema.statics.findByEmail = function(email: string) {
151
+ return this.findOne({ email: email.toLowerCase() });
152
+ };
153
+
154
+ userSchema.statics.findActiveUsers = function() {
155
+ return this.find({ isActive: true });
156
+ };
157
+
158
+ // Middleware (hooks)
159
+ userSchema.pre('save', async function(next) {
160
+ if (this.isModified('password')) {
161
+ const bcrypt = await import('bcrypt');
162
+ this.password = await bcrypt.hash(this.password, 12);
163
+ }
164
+ next();
165
+ });
166
+
167
+ export const User = mongoose.model<IUser, IUserModel>('User', userSchema);
168
+ ```
169
+
170
+ ### 2. CRUD Operations
171
+
172
+ ```typescript
173
+ // src/repositories/user.repository.ts
174
+ import { User, IUser } from '../models/user.model';
175
+ import { FilterQuery, UpdateQuery, QueryOptions } from 'mongoose';
176
+
177
+ export interface PaginationOptions {
178
+ page?: number;
179
+ limit?: number;
180
+ sort?: Record<string, 1 | -1>;
181
+ }
182
+
183
+ export interface PaginatedResult<T> {
184
+ data: T[];
185
+ pagination: {
186
+ page: number;
187
+ limit: number;
188
+ total: number;
189
+ totalPages: number;
190
+ hasMore: boolean;
191
+ };
192
+ }
193
+
194
+ export class UserRepository {
195
+ // Create
196
+ async create(userData: Partial<IUser>): Promise<IUser> {
197
+ const user = new User(userData);
198
+ return user.save();
199
+ }
200
+
201
+ async createMany(users: Partial<IUser>[]): Promise<IUser[]> {
202
+ return User.insertMany(users);
203
+ }
204
+
205
+ // Read
206
+ async findById(id: string): Promise<IUser | null> {
207
+ return User.findById(id);
208
+ }
209
+
210
+ async findByIdWithPassword(id: string): Promise<IUser | null> {
211
+ return User.findById(id).select('+password');
212
+ }
213
+
214
+ async findByEmail(email: string): Promise<IUser | null> {
215
+ return User.findByEmail(email);
216
+ }
217
+
218
+ async findOne(filter: FilterQuery<IUser>): Promise<IUser | null> {
219
+ return User.findOne(filter);
220
+ }
221
+
222
+ async find(
223
+ filter: FilterQuery<IUser>,
224
+ options: PaginationOptions = {}
225
+ ): Promise<PaginatedResult<IUser>> {
226
+ const { page = 1, limit = 20, sort = { createdAt: -1 } } = options;
227
+ const skip = (page - 1) * limit;
228
+
229
+ const [data, total] = await Promise.all([
230
+ User.find(filter).sort(sort).skip(skip).limit(limit),
231
+ User.countDocuments(filter),
232
+ ]);
233
+
234
+ return {
235
+ data,
236
+ pagination: {
237
+ page,
238
+ limit,
239
+ total,
240
+ totalPages: Math.ceil(total / limit),
241
+ hasMore: page * limit < total,
242
+ },
243
+ };
244
+ }
245
+
246
+ // Update
247
+ async updateById(
248
+ id: string,
249
+ update: UpdateQuery<IUser>,
250
+ options: QueryOptions = {}
251
+ ): Promise<IUser | null> {
252
+ return User.findByIdAndUpdate(id, update, {
253
+ new: true,
254
+ runValidators: true,
255
+ ...options,
256
+ });
257
+ }
258
+
259
+ async updateOne(
260
+ filter: FilterQuery<IUser>,
261
+ update: UpdateQuery<IUser>
262
+ ): Promise<IUser | null> {
263
+ return User.findOneAndUpdate(filter, update, {
264
+ new: true,
265
+ runValidators: true,
266
+ });
267
+ }
268
+
269
+ async updateMany(
270
+ filter: FilterQuery<IUser>,
271
+ update: UpdateQuery<IUser>
272
+ ): Promise<{ modifiedCount: number }> {
273
+ const result = await User.updateMany(filter, update);
274
+ return { modifiedCount: result.modifiedCount };
275
+ }
276
+
277
+ // Delete
278
+ async deleteById(id: string): Promise<IUser | null> {
279
+ return User.findByIdAndDelete(id);
280
+ }
281
+
282
+ async deleteMany(filter: FilterQuery<IUser>): Promise<{ deletedCount: number }> {
283
+ const result = await User.deleteMany(filter);
284
+ return { deletedCount: result.deletedCount };
285
+ }
286
+
287
+ // Soft delete
288
+ async softDelete(id: string): Promise<IUser | null> {
289
+ return this.updateById(id, { isActive: false });
290
+ }
291
+
292
+ // Exists check
293
+ async exists(filter: FilterQuery<IUser>): Promise<boolean> {
294
+ const result = await User.exists(filter);
295
+ return !!result;
296
+ }
297
+
298
+ // Count
299
+ async count(filter: FilterQuery<IUser> = {}): Promise<number> {
300
+ return User.countDocuments(filter);
301
+ }
302
+ }
303
+ ```
304
+
305
+ ### 3. Aggregation Pipelines
306
+
307
+ ```typescript
308
+ // src/services/analytics.service.ts
309
+ import { User } from '../models/user.model';
310
+ import { Order } from '../models/order.model';
311
+
312
+ export class AnalyticsService {
313
+ // User statistics by role
314
+ async getUserStatsByRole() {
315
+ return User.aggregate([
316
+ { $match: { isActive: true } },
317
+ {
318
+ $group: {
319
+ _id: '$role',
320
+ count: { $sum: 1 },
321
+ avgAddresses: { $avg: { $size: '$addresses' } },
322
+ },
323
+ },
324
+ { $sort: { count: -1 } },
325
+ ]);
326
+ }
327
+
328
+ // Monthly user registrations
329
+ async getMonthlyRegistrations(year: number) {
330
+ return User.aggregate([
331
+ {
332
+ $match: {
333
+ createdAt: {
334
+ $gte: new Date(`${year}-01-01`),
335
+ $lt: new Date(`${year + 1}-01-01`),
336
+ },
337
+ },
338
+ },
339
+ {
340
+ $group: {
341
+ _id: { $month: '$createdAt' },
342
+ count: { $sum: 1 },
343
+ },
344
+ },
345
+ {
346
+ $project: {
347
+ _id: 0,
348
+ month: '$_id',
349
+ count: 1,
350
+ },
351
+ },
352
+ { $sort: { month: 1 } },
353
+ ]);
354
+ }
355
+
356
+ // Order revenue by product category
357
+ async getRevenueByCategory(startDate: Date, endDate: Date) {
358
+ return Order.aggregate([
359
+ {
360
+ $match: {
361
+ status: 'completed',
362
+ createdAt: { $gte: startDate, $lte: endDate },
363
+ },
364
+ },
365
+ { $unwind: '$items' },
366
+ {
367
+ $lookup: {
368
+ from: 'products',
369
+ localField: 'items.productId',
370
+ foreignField: '_id',
371
+ as: 'product',
372
+ },
373
+ },
374
+ { $unwind: '$product' },
375
+ {
376
+ $group: {
377
+ _id: '$product.category',
378
+ totalRevenue: { $sum: { $multiply: ['$items.quantity', '$items.price'] } },
379
+ totalQuantity: { $sum: '$items.quantity' },
380
+ orderCount: { $sum: 1 },
381
+ },
382
+ },
383
+ {
384
+ $project: {
385
+ _id: 0,
386
+ category: '$_id',
387
+ totalRevenue: { $round: ['$totalRevenue', 2] },
388
+ totalQuantity: 1,
389
+ orderCount: 1,
390
+ avgOrderValue: {
391
+ $round: [{ $divide: ['$totalRevenue', '$orderCount'] }, 2],
392
+ },
393
+ },
394
+ },
395
+ { $sort: { totalRevenue: -1 } },
396
+ ]);
397
+ }
398
+
399
+ // Top customers with order summary
400
+ async getTopCustomers(limit: number = 10) {
401
+ return Order.aggregate([
402
+ { $match: { status: 'completed' } },
403
+ {
404
+ $group: {
405
+ _id: '$userId',
406
+ totalOrders: { $sum: 1 },
407
+ totalSpent: { $sum: '$total' },
408
+ avgOrderValue: { $avg: '$total' },
409
+ lastOrderDate: { $max: '$createdAt' },
410
+ },
411
+ },
412
+ {
413
+ $lookup: {
414
+ from: 'users',
415
+ localField: '_id',
416
+ foreignField: '_id',
417
+ as: 'user',
418
+ },
419
+ },
420
+ { $unwind: '$user' },
421
+ {
422
+ $project: {
423
+ _id: 0,
424
+ userId: '$_id',
425
+ email: '$user.email',
426
+ name: {
427
+ $concat: ['$user.profile.firstName', ' ', '$user.profile.lastName'],
428
+ },
429
+ totalOrders: 1,
430
+ totalSpent: { $round: ['$totalSpent', 2] },
431
+ avgOrderValue: { $round: ['$avgOrderValue', 2] },
432
+ lastOrderDate: 1,
433
+ },
434
+ },
435
+ { $sort: { totalSpent: -1 } },
436
+ { $limit: limit },
437
+ ]);
438
+ }
439
+
440
+ // Search with text score
441
+ async searchProducts(query: string, options: { category?: string; limit?: number }) {
442
+ const pipeline: any[] = [
443
+ {
444
+ $search: {
445
+ index: 'products_search',
446
+ text: {
447
+ query,
448
+ path: ['name', 'description', 'tags'],
449
+ fuzzy: { maxEdits: 1 },
450
+ },
451
+ },
452
+ },
453
+ {
454
+ $addFields: {
455
+ score: { $meta: 'searchScore' },
456
+ },
457
+ },
458
+ ];
459
+
460
+ if (options.category) {
461
+ pipeline.push({ $match: { category: options.category } });
462
+ }
463
+
464
+ pipeline.push(
465
+ { $sort: { score: -1 } },
466
+ { $limit: options.limit || 20 }
467
+ );
468
+
469
+ return Product.aggregate(pipeline);
470
+ }
471
+ }
472
+ ```
473
+
474
+ ### 4. Transactions
475
+
476
+ ```typescript
477
+ // src/services/order.service.ts
478
+ import mongoose from 'mongoose';
479
+ import { Order } from '../models/order.model';
480
+ import { Product } from '../models/product.model';
481
+ import { User } from '../models/user.model';
482
+
483
+ export class OrderService {
484
+ async createOrder(userId: string, items: Array<{ productId: string; quantity: number }>) {
485
+ const session = await mongoose.startSession();
486
+
487
+ try {
488
+ session.startTransaction();
489
+
490
+ // Validate user
491
+ const user = await User.findById(userId).session(session);
492
+ if (!user) {
493
+ throw new Error('User not found');
494
+ }
495
+
496
+ // Calculate order total and validate stock
497
+ let total = 0;
498
+ const orderItems = [];
499
+
500
+ for (const item of items) {
501
+ const product = await Product.findById(item.productId).session(session);
502
+ if (!product) {
503
+ throw new Error(`Product ${item.productId} not found`);
504
+ }
505
+
506
+ if (product.stock < item.quantity) {
507
+ throw new Error(`Insufficient stock for ${product.name}`);
508
+ }
509
+
510
+ // Decrement stock
511
+ await Product.updateOne(
512
+ { _id: item.productId },
513
+ { $inc: { stock: -item.quantity } },
514
+ { session }
515
+ );
516
+
517
+ const itemTotal = product.price * item.quantity;
518
+ total += itemTotal;
519
+
520
+ orderItems.push({
521
+ productId: product._id,
522
+ name: product.name,
523
+ price: product.price,
524
+ quantity: item.quantity,
525
+ total: itemTotal,
526
+ });
527
+ }
528
+
529
+ // Create order
530
+ const [order] = await Order.create([{
531
+ userId,
532
+ items: orderItems,
533
+ total,
534
+ status: 'pending',
535
+ }], { session });
536
+
537
+ await session.commitTransaction();
538
+ return order;
539
+ } catch (error) {
540
+ await session.abortTransaction();
541
+ throw error;
542
+ } finally {
543
+ session.endSession();
544
+ }
545
+ }
546
+
547
+ async cancelOrder(orderId: string) {
548
+ const session = await mongoose.startSession();
549
+
550
+ try {
551
+ session.startTransaction();
552
+
553
+ const order = await Order.findById(orderId).session(session);
554
+ if (!order) {
555
+ throw new Error('Order not found');
556
+ }
557
+
558
+ if (order.status !== 'pending') {
559
+ throw new Error('Only pending orders can be cancelled');
560
+ }
561
+
562
+ // Restore stock
563
+ for (const item of order.items) {
564
+ await Product.updateOne(
565
+ { _id: item.productId },
566
+ { $inc: { stock: item.quantity } },
567
+ { session }
568
+ );
569
+ }
570
+
571
+ // Update order status
572
+ order.status = 'cancelled';
573
+ await order.save({ session });
574
+
575
+ await session.commitTransaction();
576
+ return order;
577
+ } catch (error) {
578
+ await session.abortTransaction();
579
+ throw error;
580
+ } finally {
581
+ session.endSession();
582
+ }
583
+ }
584
+ }
585
+ ```
586
+
587
+ ### 5. Connection and Configuration
588
+
589
+ ```typescript
590
+ // src/config/database.ts
591
+ import mongoose from 'mongoose';
592
+
593
+ interface DatabaseConfig {
594
+ uri: string;
595
+ options?: mongoose.ConnectOptions;
596
+ }
597
+
598
+ export async function connectDatabase(config: DatabaseConfig): Promise<void> {
599
+ const defaultOptions: mongoose.ConnectOptions = {
600
+ maxPoolSize: 10,
601
+ serverSelectionTimeoutMS: 5000,
602
+ socketTimeoutMS: 45000,
603
+ family: 4,
604
+ };
605
+
606
+ mongoose.set('strictQuery', true);
607
+
608
+ mongoose.connection.on('connected', () => {
609
+ console.log('MongoDB connected successfully');
610
+ });
611
+
612
+ mongoose.connection.on('error', (err) => {
613
+ console.error('MongoDB connection error:', err);
614
+ });
615
+
616
+ mongoose.connection.on('disconnected', () => {
617
+ console.log('MongoDB disconnected');
618
+ });
619
+
620
+ process.on('SIGINT', async () => {
621
+ await mongoose.connection.close();
622
+ process.exit(0);
623
+ });
624
+
625
+ await mongoose.connect(config.uri, {
626
+ ...defaultOptions,
627
+ ...config.options,
628
+ });
629
+ }
630
+
631
+ export async function disconnectDatabase(): Promise<void> {
632
+ await mongoose.connection.close();
633
+ }
634
+
635
+ // Health check
636
+ export async function checkDatabaseHealth(): Promise<boolean> {
637
+ try {
638
+ await mongoose.connection.db.admin().ping();
639
+ return true;
640
+ } catch {
641
+ return false;
642
+ }
18
643
  }
19
644
  ```
20
645
 
21
- ## Query Patterns
646
+ ### 6. Indexing Strategies
647
+
22
648
  ```javascript
23
- // Find
24
- db.users.find({ email: /example.com/ });
25
-
26
- // Aggregation
27
- db.users.aggregate([
28
- { $match: { active: true } },
29
- { $group: { _id: "$role", count: { $sum: 1 } } }
30
- ]);
31
-
32
- // Update
33
- db.users.updateOne(
34
- { _id: id },
35
- { $set: { name: "New Name" } }
649
+ // Creating indexes for optimal query performance
650
+
651
+ // Compound index for common query patterns
652
+ db.orders.createIndex(
653
+ { userId: 1, status: 1, createdAt: -1 },
654
+ { name: 'user_status_date' }
36
655
  );
656
+
657
+ // Partial index for active records only
658
+ db.users.createIndex(
659
+ { email: 1 },
660
+ {
661
+ unique: true,
662
+ partialFilterExpression: { isActive: true },
663
+ name: 'active_users_email'
664
+ }
665
+ );
666
+
667
+ // TTL index for expiring documents
668
+ db.sessions.createIndex(
669
+ { expiresAt: 1 },
670
+ { expireAfterSeconds: 0, name: 'session_ttl' }
671
+ );
672
+
673
+ // Text index for full-text search
674
+ db.products.createIndex(
675
+ { name: 'text', description: 'text', tags: 'text' },
676
+ {
677
+ weights: { name: 10, tags: 5, description: 1 },
678
+ name: 'product_search'
679
+ }
680
+ );
681
+
682
+ // Geospatial index
683
+ db.stores.createIndex(
684
+ { location: '2dsphere' },
685
+ { name: 'store_location' }
686
+ );
687
+
688
+ // Wildcard index for dynamic fields
689
+ db.logs.createIndex(
690
+ { 'metadata.$**': 1 },
691
+ { name: 'log_metadata_wildcard' }
692
+ );
693
+ ```
694
+
695
+ ## Use Cases
696
+
697
+ ### Real-time Analytics Dashboard
698
+
699
+ ```typescript
700
+ // Aggregation for dashboard metrics
701
+ async function getDashboardMetrics(timeRange: { start: Date; end: Date }) {
702
+ const [orderStats, userStats, revenueByDay] = await Promise.all([
703
+ Order.aggregate([
704
+ {
705
+ $match: {
706
+ createdAt: { $gte: timeRange.start, $lte: timeRange.end },
707
+ },
708
+ },
709
+ {
710
+ $group: {
711
+ _id: '$status',
712
+ count: { $sum: 1 },
713
+ total: { $sum: '$total' },
714
+ },
715
+ },
716
+ ]),
717
+
718
+ User.aggregate([
719
+ {
720
+ $facet: {
721
+ total: [{ $count: 'count' }],
722
+ newUsers: [
723
+ {
724
+ $match: {
725
+ createdAt: { $gte: timeRange.start, $lte: timeRange.end },
726
+ },
727
+ },
728
+ { $count: 'count' },
729
+ ],
730
+ byRole: [{ $group: { _id: '$role', count: { $sum: 1 } } }],
731
+ },
732
+ },
733
+ ]),
734
+
735
+ Order.aggregate([
736
+ {
737
+ $match: {
738
+ status: 'completed',
739
+ createdAt: { $gte: timeRange.start, $lte: timeRange.end },
740
+ },
741
+ },
742
+ {
743
+ $group: {
744
+ _id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } },
745
+ revenue: { $sum: '$total' },
746
+ orders: { $sum: 1 },
747
+ },
748
+ },
749
+ { $sort: { _id: 1 } },
750
+ ]),
751
+ ]);
752
+
753
+ return { orderStats, userStats: userStats[0], revenueByDay };
754
+ }
755
+ ```
756
+
757
+ ### Change Streams for Real-time Updates
758
+
759
+ ```typescript
760
+ // Watch for real-time changes
761
+ async function watchOrderChanges(callback: (change: any) => void) {
762
+ const changeStream = Order.watch([
763
+ { $match: { operationType: { $in: ['insert', 'update'] } } },
764
+ ], { fullDocument: 'updateLookup' });
765
+
766
+ changeStream.on('change', (change) => {
767
+ callback({
768
+ type: change.operationType,
769
+ document: change.fullDocument,
770
+ timestamp: change.clusterTime,
771
+ });
772
+ });
773
+
774
+ return () => changeStream.close();
775
+ }
37
776
  ```
38
777
 
39
778
  ## Best Practices
40
- - Design for queries
41
- - Embed related data
42
- - Use indexes
43
- - Avoid deep nesting
779
+
780
+ ### Do's
781
+
782
+ - Design schemas based on query patterns
783
+ - Use appropriate indexes for queries
784
+ - Implement proper error handling
785
+ - Use transactions for multi-document operations
786
+ - Set up connection pooling
787
+ - Use lean() for read-only queries
788
+ - Implement pagination for large datasets
789
+ - Use aggregation for complex queries
790
+ - Monitor slow queries
791
+ - Set up replica sets for production
792
+
793
+ ### Don'ts
794
+
795
+ - Don't embed large arrays in documents
796
+ - Don't create too many indexes
797
+ - Don't use $where or mapReduce
798
+ - Don't ignore index usage in queries
799
+ - Don't skip validation
800
+ - Don't store large files directly
801
+ - Don't use synchronous operations
802
+ - Don't ignore connection errors
803
+ - Don't hardcode connection strings
804
+ - Don't skip backups
805
+
806
+ ## References
807
+
808
+ - [MongoDB Documentation](https://docs.mongodb.com/)
809
+ - [Mongoose Documentation](https://mongoosejs.com/docs/)
810
+ - [MongoDB University](https://university.mongodb.com/)
811
+ - [MongoDB Performance Best Practices](https://www.mongodb.com/docs/manual/administration/analyzing-mongodb-performance/)
812
+ - [Schema Design Patterns](https://www.mongodb.com/blog/post/building-with-patterns-a-summary)