nx-mongo 3.6.0 → 3.8.1

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nx-mongo
2
2
 
3
- **Version:** 3.6.0
3
+ **Version:** 3.8.0
4
4
 
5
5
  A lightweight, feature-rich MongoDB helper library for Node.js and TypeScript. Provides a simple, intuitive API for common MongoDB operations with built-in retry logic, pagination, transactions, config-driven ref mapping, and signature-based deduplication.
6
6
 
@@ -31,24 +31,39 @@ npm install nx-mongo
31
31
  ```typescript
32
32
  import { SimpleMongoHelper } from 'nx-mongo';
33
33
 
34
- const helper = new SimpleMongoHelper('mongodb://localhost:27017/my-database');
34
+ // Connection string: database name is ignored/stripped automatically
35
+ // Use base connection string: mongodb://localhost:27017/
36
+ const helper = new SimpleMongoHelper('mongodb://localhost:27017/');
35
37
 
36
38
  // Initialize connection
37
39
  await helper.initialize();
38
40
 
39
- // Insert a document
41
+ // Insert a document (defaults to 'admin' database)
40
42
  await helper.insert('users', {
41
43
  name: 'John Doe',
42
44
  email: 'john@example.com',
43
45
  age: 30
44
46
  });
45
47
 
46
- // Find documents
48
+ // Insert into a specific database
49
+ await helper.insert('users', {
50
+ name: 'Jane Doe',
51
+ email: 'jane@example.com',
52
+ age: 28
53
+ }, {}, 'mydb'); // Specify database name
54
+
55
+ // Find documents from 'admin' database (default)
47
56
  const users = await helper.loadCollection('users');
48
57
 
58
+ // Find documents from specific database
59
+ const mydbUsers = await helper.loadCollection('users', {}, undefined, 'mydb');
60
+
49
61
  // Find one document
50
62
  const user = await helper.findOne('users', { email: 'john@example.com' });
51
63
 
64
+ // Find from specific database
65
+ const mydbUser = await helper.findOne('users', { email: 'jane@example.com' }, undefined, 'mydb');
66
+
52
67
  // Update document
53
68
  await helper.update(
54
69
  'users',
@@ -56,6 +71,15 @@ await helper.update(
56
71
  { $set: { age: 31 } }
57
72
  );
58
73
 
74
+ // Update in specific database
75
+ await helper.update(
76
+ 'users',
77
+ { email: 'jane@example.com' },
78
+ { $set: { age: 29 } },
79
+ undefined,
80
+ 'mydb'
81
+ );
82
+
59
83
  // Delete document
60
84
  await helper.delete('users', { email: 'john@example.com' });
61
85
 
@@ -63,6 +87,8 @@ await helper.delete('users', { email: 'john@example.com' });
63
87
  await helper.disconnect();
64
88
  ```
65
89
 
90
+ **Note:** The connection string database name (if present) is automatically stripped. All operations default to the `'admin'` database unless you specify a different database name as the last parameter.
91
+
66
92
  ## API Reference
67
93
 
68
94
  ### Constructor
@@ -72,7 +98,8 @@ new SimpleMongoHelper(connectionString: string, retryOptions?: RetryOptions)
72
98
  ```
73
99
 
74
100
  **Parameters:**
75
- - `connectionString` - MongoDB connection string
101
+ - `connectionString` - MongoDB base connection string (database name is automatically stripped if present)
102
+ - Example: `'mongodb://localhost:27017/'` or `'mongodb://localhost:27017/admin'` (both work the same)
76
103
  - `retryOptions` (optional) - Retry configuration
77
104
  - `maxRetries?: number` - Maximum retry attempts (default: 3)
78
105
  - `retryDelay?: number` - Initial retry delay in ms (default: 1000)
@@ -80,12 +107,15 @@ new SimpleMongoHelper(connectionString: string, retryOptions?: RetryOptions)
80
107
 
81
108
  **Example:**
82
109
  ```typescript
110
+ // Database name in connection string is ignored/stripped
83
111
  const helper = new SimpleMongoHelper(
84
- 'mongodb://localhost:27017/my-db',
112
+ 'mongodb://localhost:27017/', // or 'mongodb://localhost:27017/admin'
85
113
  { maxRetries: 5, retryDelay: 2000 }
86
114
  );
87
115
  ```
88
116
 
117
+ **Important:** The database name in the connection string is automatically stripped. All operations default to the `'admin'` database unless you specify a different database name per operation.
118
+
89
119
  ### Connection Methods
90
120
 
91
121
  #### `testConnection(): Promise<{ success: boolean; error?: { type: string; message: string; details?: string } }>`
@@ -103,9 +133,26 @@ Tests the MongoDB connection and returns detailed error information if it fails.
103
133
  ```typescript
104
134
  const result = await helper.testConnection();
105
135
  if (!result.success) {
106
- console.error('Connection test failed:', result.error?.message);
107
- console.error('Details:', result.error?.details);
108
- // Handle error based on result.error?.type
136
+ console.error('Connection test failed!');
137
+ console.error('Error Type:', result.error?.type);
138
+ console.error('Error Message:', result.error?.message);
139
+ console.error('Error Details:', result.error?.details);
140
+
141
+ // Handle error based on type
142
+ switch (result.error?.type) {
143
+ case 'connection_failed':
144
+ console.error('Cannot connect to MongoDB server. Check if server is running.');
145
+ // On Windows, try using 127.0.0.1 instead of localhost
146
+ break;
147
+ case 'authentication_failed':
148
+ console.error('Invalid credentials. Check username and password.');
149
+ break;
150
+ case 'invalid_connection_string':
151
+ console.error('Connection string format is invalid.');
152
+ break;
153
+ default:
154
+ console.error('Unknown error occurred.');
155
+ }
109
156
  } else {
110
157
  console.log('Connection test passed!');
111
158
  await helper.initialize();
@@ -120,6 +167,12 @@ if (!result.success) {
120
167
  - `config_error` - Configuration issues
121
168
  - `unknown` - Unexpected error
122
169
 
170
+ **Troubleshooting Tips:**
171
+ - **Windows users**: If using `localhost` fails, try `127.0.0.1` instead (e.g., `mongodb://127.0.0.1:27017/`) to avoid IPv6 resolution issues
172
+ - **Connection timeout**: Verify MongoDB is running and accessible on the specified host and port
173
+ - **Connection refused**: Check if MongoDB is listening on the correct port (default: 27017)
174
+ - **Authentication failed**: Verify username and password in the connection string
175
+
123
176
  #### `initialize(): Promise<void>`
124
177
 
125
178
  Establishes MongoDB connection with automatic retry logic. Must be called before using other methods.
@@ -144,7 +197,7 @@ await helper.disconnect();
144
197
 
145
198
  ### Query Methods
146
199
 
147
- #### `loadCollection<T>(collectionName: string, query?: Filter<T>, options?: PaginationOptions): Promise<WithId<T>[] | PaginatedResult<T>>`
200
+ #### `loadCollection<T>(collectionName: string, query?: Filter<T>, options?: PaginationOptions, database?: string): Promise<WithId<T>[] | PaginatedResult<T>>`
148
201
 
149
202
  Loads documents from a collection with optional query filter and pagination.
150
203
 
@@ -155,6 +208,7 @@ Loads documents from a collection with optional query filter and pagination.
155
208
  - `page?: number` - Page number (1-indexed)
156
209
  - `limit?: number` - Documents per page
157
210
  - `sort?: Sort` - Sort specification
211
+ - `database` (optional) - Database name (defaults to `'admin'`)
158
212
 
159
213
  **Returns:**
160
214
  - Without pagination: `WithId<T>[]`
@@ -162,9 +216,12 @@ Loads documents from a collection with optional query filter and pagination.
162
216
 
163
217
  **Examples:**
164
218
  ```typescript
165
- // Load all documents
219
+ // Load all documents from 'admin' database (default)
166
220
  const allUsers = await helper.loadCollection('users');
167
221
 
222
+ // Load from specific database
223
+ const mydbUsers = await helper.loadCollection('users', {}, undefined, 'mydb');
224
+
168
225
  // Load with query
169
226
  const activeUsers = await helper.loadCollection('users', { active: true });
170
227
 
@@ -180,9 +237,16 @@ const result = await helper.loadCollection('users', {}, {
180
237
  // result.totalPages - total pages
181
238
  // result.hasNext - has next page
182
239
  // result.hasPrev - has previous page
240
+
241
+ // Load with pagination from specific database
242
+ const mydbResult = await helper.loadCollection('users', {}, {
243
+ page: 1,
244
+ limit: 10,
245
+ sort: { createdAt: -1 }
246
+ }, 'mydb');
183
247
  ```
184
248
 
185
- #### `findOne<T>(collectionName: string, query: Filter<T>, options?: { sort?: Sort; projection?: Document }): Promise<WithId<T> | null>`
249
+ #### `findOne<T>(collectionName: string, query: Filter<T>, options?: { sort?: Sort; projection?: Document }, database?: string): Promise<WithId<T> | null>`
186
250
 
187
251
  Finds a single document in a collection.
188
252
 
@@ -192,6 +256,7 @@ Finds a single document in a collection.
192
256
  - `options` (optional) - Find options
193
257
  - `sort?: Sort` - Sort specification
194
258
  - `projection?: Document` - Field projection
259
+ - `database` (optional) - Database name (defaults to `'admin'`)
195
260
 
196
261
  **Example:**
197
262
  ```typescript
@@ -201,7 +266,7 @@ const latestUser = await helper.findOne('users', {}, { sort: { createdAt: -1 } }
201
266
 
202
267
  ### Insert Methods
203
268
 
204
- #### `insert<T>(collectionName: string, data: T | T[], options?: { session?: ClientSession }): Promise<any>`
269
+ #### `insert<T>(collectionName: string, data: T | T[], options?: { session?: ClientSession }, database?: string): Promise<any>`
205
270
 
206
271
  Inserts one or more documents into a collection.
207
272
 
@@ -234,7 +299,7 @@ await session.withTransaction(async () => {
234
299
 
235
300
  ### Update Methods
236
301
 
237
- #### `update<T>(collectionName: string, filter: Filter<T>, updateData: UpdateFilter<T>, options?: { upsert?: boolean; multi?: boolean; session?: ClientSession }): Promise<any>`
302
+ #### `update<T>(collectionName: string, filter: Filter<T>, updateData: UpdateFilter<T>, options?: { upsert?: boolean; multi?: boolean; session?: ClientSession }, database?: string): Promise<any>`
238
303
 
239
304
  Updates documents in a collection.
240
305
 
@@ -275,7 +340,7 @@ await helper.update(
275
340
 
276
341
  ### Delete Methods
277
342
 
278
- #### `delete<T>(collectionName: string, filter: Filter<T>, options?: { multi?: boolean }): Promise<any>`
343
+ #### `delete<T>(collectionName: string, filter: Filter<T>, options?: { multi?: boolean }, database?: string): Promise<any>`
279
344
 
280
345
  Deletes documents from a collection.
281
346
 
@@ -314,6 +379,7 @@ Merges two collections into a new target collection using various strategies (in
314
379
  - `onUnmatched1` - (Deprecated: use `joinType` instead) What to do with unmatched records from collection 1: 'include' | 'skip' (default: 'include')
315
380
  - `onUnmatched2` - (Deprecated: use `joinType` instead) What to do with unmatched records from collection 2: 'include' | 'skip' (default: 'include')
316
381
  - `session` - Optional transaction session
382
+ - `database` - Optional database name (defaults to `'admin'`)
317
383
 
318
384
  **Returns:**
319
385
  ```typescript
@@ -491,10 +557,15 @@ const result6 = await helper.mergeCollections({
491
557
 
492
558
  ### Count Methods
493
559
 
494
- #### `countDocuments<T>(collectionName: string, query?: Filter<T>): Promise<number>`
560
+ #### `countDocuments<T>(collectionName: string, query?: Filter<T>, database?: string): Promise<number>`
495
561
 
496
562
  Counts documents matching a query (accurate count).
497
563
 
564
+ **Parameters:**
565
+ - `collectionName` - Name of the collection
566
+ - `query` (optional) - MongoDB query filter
567
+ - `database` (optional) - Database name (defaults to `'admin'`)
568
+
498
569
  **Example:**
499
570
  ```typescript
500
571
  const userCount = await helper.countDocuments('users');
@@ -512,10 +583,15 @@ const estimatedCount = await helper.estimatedDocumentCount('users');
512
583
 
513
584
  ### Aggregation Methods
514
585
 
515
- #### `aggregate<T>(collectionName: string, pipeline: Document[]): Promise<T[]>`
586
+ #### `aggregate<T>(collectionName: string, pipeline: Document[], database?: string): Promise<T[]>`
516
587
 
517
588
  Runs an aggregation pipeline on a collection.
518
589
 
590
+ **Parameters:**
591
+ - `collectionName` - Name of the collection
592
+ - `pipeline` - Array of aggregation pipeline stages
593
+ - `database` (optional) - Database name (defaults to `'admin'`)
594
+
519
595
  **Example:**
520
596
  ```typescript
521
597
  const result = await helper.aggregate('orders', [
@@ -531,10 +607,16 @@ const result = await helper.aggregate('orders', [
531
607
 
532
608
  ### Index Methods
533
609
 
534
- #### `createIndex(collectionName: string, indexSpec: IndexSpecification, options?: CreateIndexesOptions): Promise<string>`
610
+ #### `createIndex(collectionName: string, indexSpec: IndexSpecification, options?: CreateIndexesOptions, database?: string): Promise<string>`
535
611
 
536
612
  Creates an index on a collection.
537
613
 
614
+ **Parameters:**
615
+ - `collectionName` - Name of the collection
616
+ - `indexSpec` - Index specification
617
+ - `options` (optional) - Index creation options
618
+ - `database` (optional) - Database name (defaults to `'admin'`)
619
+
538
620
  **Example:**
539
621
  ```typescript
540
622
  // Simple index
@@ -547,19 +629,28 @@ await helper.createIndex('users', { email: 1 }, { unique: true });
547
629
  await helper.createIndex('users', { email: 1, createdAt: -1 });
548
630
  ```
549
631
 
550
- #### `dropIndex(collectionName: string, indexName: string): Promise<any>`
632
+ #### `dropIndex(collectionName: string, indexName: string, database?: string): Promise<any>`
551
633
 
552
634
  Drops an index from a collection.
553
635
 
636
+ **Parameters:**
637
+ - `collectionName` - Name of the collection
638
+ - `indexName` - Name of the index to drop
639
+ - `database` (optional) - Database name (defaults to `'admin'`)
640
+
554
641
  **Example:**
555
642
  ```typescript
556
643
  await helper.dropIndex('users', 'email_1');
557
644
  ```
558
645
 
559
- #### `listIndexes(collectionName: string): Promise<Document[]>`
646
+ #### `listIndexes(collectionName: string, database?: string): Promise<Document[]>`
560
647
 
561
648
  Lists all indexes on a collection.
562
649
 
650
+ **Parameters:**
651
+ - `collectionName` - Name of the collection
652
+ - `database` (optional) - Database name (defaults to `'admin'`)
653
+
563
654
  **Example:**
564
655
  ```typescript
565
656
  const indexes = await helper.listIndexes('users');
@@ -621,6 +712,11 @@ interface HelperConfig {
621
712
  uniqueIndexKeys?: string[]; // Unique index keys (default: ["provider","key"])
622
713
  provider?: string; // Default provider namespace for this helper instance
623
714
  };
715
+ databases?: Array<{
716
+ ref: string; // Reference identifier
717
+ type: string; // Type identifier
718
+ database: string; // Database name to use
719
+ }>;
624
720
  }
625
721
  ```
626
722
 
@@ -669,15 +765,101 @@ Sets or updates the configuration for ref-based operations.
669
765
  helper.useConfig(config);
670
766
  ```
671
767
 
768
+ ### Database Selection via Ref/Type Map
769
+
770
+ The helper supports config-driven database selection using `ref` and `type` parameters. This allows you to map logical identifiers to database names without hardcoding them in your application code.
771
+
772
+ **Configuration:**
773
+
774
+ ```typescript
775
+ const config = {
776
+ // ... inputs, outputs, etc.
777
+ databases: [
778
+ { ref: "app1", type: "production", database: "app1_prod" },
779
+ { ref: "app1", type: "staging", database: "app1_staging" },
780
+ { ref: "app2", type: "production", database: "app2_prod" },
781
+ { ref: "app2", type: "staging", database: "app2_staging" },
782
+ ]
783
+ };
784
+ ```
785
+
786
+ **Usage in CRUD Operations:**
787
+
788
+ All CRUD operations now support optional `ref` and `type` parameters for automatic database resolution:
789
+
790
+ ```typescript
791
+ // Priority 1: Direct database parameter (highest priority)
792
+ await helper.insert('users', { name: 'John' }, {}, 'mydb');
793
+
794
+ // Priority 2: Using ref + type (exact match)
795
+ await helper.insert('users', { name: 'John' }, {}, undefined, 'app1', 'production');
796
+ // Resolves to 'app1_prod' database
797
+
798
+ // Priority 3: Using ref alone (must have exactly one match)
799
+ await helper.insert('users', { name: 'John' }, {}, undefined, 'app1');
800
+ // Throws error if multiple matches found
801
+
802
+ // Priority 4: Using type alone (must have exactly one match)
803
+ await helper.insert('users', { name: 'John' }, {}, undefined, undefined, 'production');
804
+ // Throws error if multiple matches found
805
+ ```
806
+
807
+ **Database Resolution Priority:**
808
+
809
+ 1. **Direct `database` parameter** - If provided, it's used immediately (highest priority)
810
+ 2. **`ref` + `type`** - If both provided, finds exact match in databases map
811
+ 3. **`ref` alone** - If only ref provided, finds entries matching ref (must be exactly one)
812
+ 4. **`type` alone** - If only type provided, finds entries matching type (must be exactly one)
813
+ 5. **Default** - If none provided, defaults to `'admin'` database
814
+
815
+ **Error Handling:**
816
+
817
+ - If no match found: throws error with descriptive message
818
+ - If multiple matches found: throws error suggesting to use additional parameter to narrow down
819
+
820
+ **Example:**
821
+
822
+ ```typescript
823
+ const config = {
824
+ databases: [
825
+ { ref: "tenant1", type: "prod", database: "tenant1_prod" },
826
+ { ref: "tenant1", type: "dev", database: "tenant1_dev" },
827
+ { ref: "tenant2", type: "prod", database: "tenant2_prod" },
828
+ ]
829
+ };
830
+
831
+ const helper = new SimpleMongoHelper('mongodb://localhost:27017/', undefined, config);
832
+ await helper.initialize();
833
+
834
+ // Use ref + type for exact match
835
+ await helper.insert('users', { name: 'John' }, {}, undefined, 'tenant1', 'prod');
836
+ // Uses 'tenant1_prod' database
837
+
838
+ // Use ref alone (only works if exactly one match)
839
+ // This would throw error because tenant1 has 2 matches (prod and dev)
840
+ // await helper.insert('users', { name: 'John' }, {}, undefined, 'tenant1');
841
+
842
+ // Use type alone (only works if exactly one match)
843
+ // This would throw error because 'prod' has 2 matches (tenant1 and tenant2)
844
+ // await helper.insert('users', { name: 'John' }, {}, undefined, undefined, 'prod');
845
+ ```
846
+
672
847
  ### Ref-based Operations
673
848
 
674
- #### `loadByRef<T>(ref: string, options?: PaginationOptions & { session?: ClientSession }): Promise<WithId<T>[] | PaginatedResult<T>>`
849
+ #### `loadByRef<T>(ref: string, options?: PaginationOptions & { session?: ClientSession; database?: string; ref?: string; type?: string }): Promise<WithId<T>[] | PaginatedResult<T>>`
675
850
 
676
851
  Loads data from a collection using a ref name from the configuration.
677
852
 
678
853
  **Parameters:**
679
854
  - `ref` - Application-level reference name (must exist in config.inputs)
680
855
  - `options` (optional) - Pagination and session options
856
+ - `page?: number` - Page number (1-indexed)
857
+ - `limit?: number` - Documents per page
858
+ - `sort?: Sort` - Sort specification
859
+ - `session?: ClientSession` - Transaction session
860
+ - `database?: string` - Database name (defaults to `'admin'`)
861
+ - `ref?: string` - Optional ref for database resolution
862
+ - `type?: string` - Optional type for database resolution
681
863
 
682
864
  **Example:**
683
865
 
@@ -694,7 +876,7 @@ const result = await helper.loadByRef('topology', {
694
876
  });
695
877
  ```
696
878
 
697
- #### `writeByRef(ref: string, documents: any[], options?: { session?: ClientSession; ensureIndex?: boolean }): Promise<WriteByRefResult>`
879
+ #### `writeByRef(ref: string, documents: any[], options?: { session?: ClientSession; ensureIndex?: boolean; database?: string; ref?: string; type?: string }): Promise<WriteByRefResult>`
698
880
 
699
881
  Writes documents to a collection using a ref name from the configuration. Supports signature-based deduplication and append/replace modes.
700
882
 
@@ -704,6 +886,9 @@ Writes documents to a collection using a ref name from the configuration. Suppor
704
886
  - `options` (optional) - Write options
705
887
  - `session?: ClientSession` - Transaction session
706
888
  - `ensureIndex?: boolean` - Whether to ensure signature index exists (default: true)
889
+ - `database?: string` - Database name (defaults to `'admin'`)
890
+ - `ref?: string` - Optional ref for database resolution
891
+ - `type?: string` - Optional type for database resolution
707
892
 
708
893
  **Returns:**
709
894
 
@@ -732,6 +917,15 @@ await helper.writeByRef('prioritizedPaths', prioritizedDocs);
732
917
 
733
918
  Writes documents to a collection and optionally marks a stage as complete atomically. See the [Progress Tracking](#progress-tracking) section for details and examples.
734
919
 
920
+ **Parameters:**
921
+ - `ref` - Application-level reference name (must exist in config.outputs)
922
+ - `documents` - Array of documents to write
923
+ - `options` (optional) - Write and completion options
924
+ - `session?: ClientSession` - Transaction session
925
+ - `ensureIndex?: boolean` - Whether to ensure signature index exists (default: true)
926
+ - `database?: string` - Database name (defaults to `'admin'`)
927
+ - `complete?: object` - Stage completion information (optional)
928
+
735
929
  **Example:**
736
930
 
737
931
  ```typescript
@@ -1323,6 +1517,29 @@ Contributions are welcome! Please feel free to submit a Pull Request.
1323
1517
 
1324
1518
  ## Changelog
1325
1519
 
1520
+ ### 3.8.1
1521
+ - **Fixed `testConnection()` error reporting bug**: Improved error extraction from MongoDB error objects to prevent `[object Object]` display
1522
+ - Enhanced error handling to extract MongoDB-specific error properties (`code`, `codeName`, `errmsg`)
1523
+ - Added Windows-specific troubleshooting hints for localhost connection issues (suggests using `127.0.0.1` instead of `localhost`)
1524
+ - Improved error messages with error codes and types for better debugging
1525
+ - Updated documentation with better error handling examples
1526
+
1527
+ ### 3.8.0
1528
+ - **Database selection via ref/type map**: Added config-driven database selection using `ref` and `type` parameters
1529
+ - Added `databases` array to `HelperConfig` for mapping ref/type combinations to database names
1530
+ - All CRUD operations now support optional `ref` and `type` parameters for automatic database resolution
1531
+ - Database resolution priority: direct `database` parameter > `ref` + `type` > `ref` alone > `type` alone
1532
+ - Throws descriptive errors when no match or multiple matches found in database map
1533
+ - Updated Progress API to support database resolution via ref/type
1534
+ - Updated `loadByRef`, `writeByRef`, `writeStage`, and `mergeCollections` to support database map resolution
1535
+
1536
+ ### 3.7.0
1537
+ - **Separated database from connection string**: Database name is now specified per operation, not in connection string
1538
+ - **Multi-database support**: All operations accept optional `database` parameter (defaults to `'admin'`)
1539
+ - Connection string database name is automatically stripped if present (e.g., `mongodb://localhost:27017/admin` becomes `mongodb://localhost:27017/`)
1540
+ - Updated all methods (`insert`, `update`, `delete`, `loadCollection`, `findOne`, `countDocuments`, `aggregate`, `createIndex`, `dropIndex`, `listIndexes`, `writeByRef`, `loadByRef`, `mergeCollections`, `writeStage`, and progress API) to support per-operation database selection
1541
+ - **Breaking change**: No backward compatibility - all code must be updated to use new database parameter
1542
+
1326
1543
  ### 3.6.0
1327
1544
  - **Automatic connection cleanup**: Connections now automatically close on app exit (SIGINT, SIGTERM, beforeExit)
1328
1545
  - **Multi-instance support**: Global registry handles multiple `SimpleMongoHelper` instances gracefully