monsqlize 1.3.0 → 2.0.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.
- package/CHANGELOG.md +56 -60
- package/LICENSE +201 -21
- package/README.md +537 -1828
- package/changelogs/README.md +160 -0
- package/changelogs/v2.0.0.md +222 -0
- package/dist/cjs/index.cjs +10600 -0
- package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
- package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
- package/dist/cjs/transaction/Transaction.cjs +158 -0
- package/dist/cjs/transaction/TransactionManager.cjs +298 -0
- package/dist/esm/index.mjs +10650 -0
- package/dist/types/base.d.ts +81 -0
- package/dist/types/collection.d.ts +1031 -0
- package/dist/types/expression.d.ts +115 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/lock.d.ts +74 -0
- package/dist/types/model.d.ts +526 -0
- package/dist/types/mongodb.d.ts +49 -0
- package/dist/types/monsqlize.d.ts +491 -0
- package/dist/types/pool.d.ts +84 -0
- package/dist/types/runtime.d.ts +362 -0
- package/dist/types/saga.d.ts +143 -0
- package/dist/types/slow-query-log.d.ts +126 -0
- package/dist/types/sync.d.ts +103 -0
- package/dist/types/transaction.d.ts +132 -0
- package/package.json +67 -69
- package/index.d.ts +0 -206
- package/index.mjs +0 -52
- package/lib/cache-invalidation.js +0 -279
- package/lib/cache.js +0 -530
- package/lib/common/cursor.js +0 -59
- package/lib/common/docs-urls.js +0 -73
- package/lib/common/index-options.js +0 -223
- package/lib/common/log.js +0 -61
- package/lib/common/namespace.js +0 -22
- package/lib/common/normalize.js +0 -34
- package/lib/common/page-result.js +0 -43
- package/lib/common/runner.js +0 -57
- package/lib/common/server-features.js +0 -232
- package/lib/common/shape-builders.js +0 -27
- package/lib/common/validation.js +0 -113
- package/lib/connect.js +0 -99
- package/lib/constants.js +0 -55
- package/lib/count-queue.js +0 -188
- package/lib/distributed-cache-invalidator.js +0 -260
- package/lib/errors.js +0 -168
- package/lib/expression/cache/ExpressionCache.js +0 -114
- package/lib/expression/compiler/ExpressionCompiler.js +0 -1090
- package/lib/expression/compiler/ExpressionCompilerExtensions.js +0 -531
- package/lib/expression/detector.js +0 -84
- package/lib/expression/factory.js +0 -29
- package/lib/expression/index.js +0 -19
- package/lib/function-cache.js +0 -533
- package/lib/index.js +0 -1251
- package/lib/infrastructure/ConnectionPoolManager.js +0 -464
- package/lib/infrastructure/HealthChecker.js +0 -281
- package/lib/infrastructure/PoolConfig.js +0 -199
- package/lib/infrastructure/PoolSelector.js +0 -225
- package/lib/infrastructure/PoolStats.js +0 -244
- package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -212
- package/lib/infrastructure/ssh-tunnel.js +0 -41
- package/lib/infrastructure/uri-parser.js +0 -36
- package/lib/lock/Lock.js +0 -67
- package/lib/lock/errors.js +0 -28
- package/lib/lock/index.js +0 -13
- package/lib/logger.js +0 -225
- package/lib/model/examples/test.js +0 -311
- package/lib/model/features/defaults.js +0 -161
- package/lib/model/features/populate.js +0 -568
- package/lib/model/features/relations.js +0 -120
- package/lib/model/features/soft-delete.js +0 -349
- package/lib/model/features/version.js +0 -157
- package/lib/model/features/virtuals.js +0 -219
- package/lib/model/index.js +0 -1265
- package/lib/mongodb/common/accessor-helpers.js +0 -59
- package/lib/mongodb/common/agg-pipeline.js +0 -36
- package/lib/mongodb/common/aggregation-validator.js +0 -127
- package/lib/mongodb/common/iid.js +0 -28
- package/lib/mongodb/common/lexicographic-expr.js +0 -53
- package/lib/mongodb/common/shape.js +0 -32
- package/lib/mongodb/common/sort.js +0 -39
- package/lib/mongodb/common/transaction-aware.js +0 -25
- package/lib/mongodb/connect.js +0 -234
- package/lib/mongodb/index.js +0 -639
- package/lib/mongodb/management/admin-ops.js +0 -200
- package/lib/mongodb/management/bookmark-ops.js +0 -167
- package/lib/mongodb/management/cache-ops.js +0 -50
- package/lib/mongodb/management/collection-ops.js +0 -387
- package/lib/mongodb/management/database-ops.js +0 -202
- package/lib/mongodb/management/index-ops.js +0 -475
- package/lib/mongodb/management/index.js +0 -17
- package/lib/mongodb/management/namespace.js +0 -31
- package/lib/mongodb/management/validation-ops.js +0 -268
- package/lib/mongodb/queries/aggregate.js +0 -172
- package/lib/mongodb/queries/chain.js +0 -631
- package/lib/mongodb/queries/count.js +0 -99
- package/lib/mongodb/queries/distinct.js +0 -78
- package/lib/mongodb/queries/find-and-count.js +0 -193
- package/lib/mongodb/queries/find-by-ids.js +0 -236
- package/lib/mongodb/queries/find-one-by-id.js +0 -171
- package/lib/mongodb/queries/find-one.js +0 -71
- package/lib/mongodb/queries/find-page.js +0 -618
- package/lib/mongodb/queries/find.js +0 -171
- package/lib/mongodb/queries/index.js +0 -51
- package/lib/mongodb/queries/watch.js +0 -538
- package/lib/mongodb/writes/common/batch-retry.js +0 -65
- package/lib/mongodb/writes/delete-batch.js +0 -323
- package/lib/mongodb/writes/delete-many.js +0 -181
- package/lib/mongodb/writes/delete-one.js +0 -173
- package/lib/mongodb/writes/find-one-and-delete.js +0 -203
- package/lib/mongodb/writes/find-one-and-replace.js +0 -239
- package/lib/mongodb/writes/find-one-and-update.js +0 -240
- package/lib/mongodb/writes/increment-one.js +0 -259
- package/lib/mongodb/writes/index.js +0 -46
- package/lib/mongodb/writes/insert-batch.js +0 -508
- package/lib/mongodb/writes/insert-many.js +0 -223
- package/lib/mongodb/writes/insert-one.js +0 -169
- package/lib/mongodb/writes/replace-one.js +0 -226
- package/lib/mongodb/writes/result-handler.js +0 -237
- package/lib/mongodb/writes/update-batch.js +0 -416
- package/lib/mongodb/writes/update-many.js +0 -275
- package/lib/mongodb/writes/update-one.js +0 -273
- package/lib/mongodb/writes/upsert-one.js +0 -203
- package/lib/multi-level-cache.js +0 -244
- package/lib/operators.js +0 -330
- package/lib/redis-cache-adapter.js +0 -267
- package/lib/saga/SagaContext.js +0 -67
- package/lib/saga/SagaDefinition.js +0 -32
- package/lib/saga/SagaExecutor.js +0 -201
- package/lib/saga/SagaOrchestrator.js +0 -186
- package/lib/saga/index.js +0 -11
- package/lib/slow-query-log/base-storage.js +0 -70
- package/lib/slow-query-log/batch-queue.js +0 -97
- package/lib/slow-query-log/config-manager.js +0 -196
- package/lib/slow-query-log/index.js +0 -238
- package/lib/slow-query-log/mongodb-storage.js +0 -324
- package/lib/slow-query-log/query-hash.js +0 -39
- package/lib/sync/ChangeStreamSyncManager.js +0 -405
- package/lib/sync/ResumeTokenStore.js +0 -192
- package/lib/sync/SyncConfig.js +0 -127
- package/lib/sync/SyncTarget.js +0 -240
- package/lib/sync/index.js +0 -20
- package/lib/transaction/CacheLockManager.js +0 -162
- package/lib/transaction/DistributedCacheLockManager.js +0 -475
- package/lib/transaction/Transaction.js +0 -315
- package/lib/transaction/TransactionManager.js +0 -267
- package/lib/transaction/index.js +0 -11
- package/lib/utils/objectid-converter.js +0 -632
- package/types/README.md +0 -122
- package/types/base.ts +0 -94
- package/types/batch.ts +0 -187
- package/types/cache.ts +0 -71
- package/types/chain.ts +0 -254
- package/types/collection.ts +0 -357
- package/types/expression.ts +0 -109
- package/types/function-cache.d.ts +0 -135
- package/types/lock.ts +0 -95
- package/types/model/definition.ts +0 -152
- package/types/model/index.ts +0 -10
- package/types/model/instance.ts +0 -121
- package/types/model/relations.ts +0 -121
- package/types/model/virtuals.ts +0 -32
- package/types/monsqlize.ts +0 -245
- package/types/options.ts +0 -192
- package/types/pagination.ts +0 -154
- package/types/pool.ts +0 -125
- package/types/query.ts +0 -71
- package/types/saga.ts +0 -125
- package/types/stream.ts +0 -64
- package/types/sync.ts +0 -79
- package/types/transaction.ts +0 -79
- package/types/write.ts +0 -77
package/README.md
CHANGED
|
@@ -1,1828 +1,537 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- [
|
|
32
|
-
- [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
await users.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
-
|
|
453
|
-
-
|
|
454
|
-
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const orders = await msq.collection('orders')
|
|
539
|
-
.find({ userId }).toArray();
|
|
540
|
-
return { user, orders };
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// 添加缓存(零侵入)
|
|
544
|
-
const cached = withCache(getUserProfile, {
|
|
545
|
-
ttl: 300000, // 5分钟
|
|
546
|
-
cache: msq.getCache()
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
// 使用
|
|
550
|
-
await cached('user123'); // 首次:查询数据库
|
|
551
|
-
await cached('user123'); // 再次:从缓存读取 ⚡
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
</td>
|
|
555
|
-
<td width="50%">
|
|
556
|
-
|
|
557
|
-
**核心优势**
|
|
558
|
-
|
|
559
|
-
- ✅ **零侵入** - 装饰器模式,不修改原函数
|
|
560
|
-
- ✅ **自动序列化** - 支持复杂参数(对象、Date等)
|
|
561
|
-
- ✅ **并发控制** - 防止缓存击穿
|
|
562
|
-
- ✅ **双层缓存** - 本地 + Redis,最佳性能
|
|
563
|
-
- ✅ **条件缓存** - 基于返回值决定是否缓存
|
|
564
|
-
- ✅ **统计监控** - 命中率、调用次数等
|
|
565
|
-
- ✅ **命名空间** - 多模块缓存隔离
|
|
566
|
-
- ✅ **TypeScript** - 完整类型支持
|
|
567
|
-
|
|
568
|
-
**性能提升**:
|
|
569
|
-
- 🚀 复杂业务函数:50000x
|
|
570
|
-
- 🚀 外部 API 调用:200000x
|
|
571
|
-
- 🚀 复杂计算:100000x
|
|
572
|
-
|
|
573
|
-
</td>
|
|
574
|
-
</tr>
|
|
575
|
-
</table>
|
|
576
|
-
|
|
577
|
-
**FunctionCache 类管理**:
|
|
578
|
-
|
|
579
|
-
```javascript
|
|
580
|
-
const { FunctionCache } = require('monsqlize');
|
|
581
|
-
|
|
582
|
-
const fnCache = new FunctionCache(msq, {
|
|
583
|
-
namespace: 'myApp',
|
|
584
|
-
defaultTTL: 60000
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
// 注册多个函数
|
|
588
|
-
fnCache.register('getUserProfile', getUserProfileFn);
|
|
589
|
-
fnCache.register('getOrderStats', getOrderStatsFn);
|
|
590
|
-
|
|
591
|
-
// 执行
|
|
592
|
-
await fnCache.execute('getUserProfile', 'user123');
|
|
593
|
-
|
|
594
|
-
// 失效缓存
|
|
595
|
-
await fnCache.invalidate('getUserProfile', 'user123');
|
|
596
|
-
|
|
597
|
-
// 查看统计
|
|
598
|
-
const stats = fnCache.getStats('getUserProfile');
|
|
599
|
-
console.log('命中率:', stats.hitRate);
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
📖 [完整文档](./docs/function-cache.md) · [键生成机制](./docs/function-cache-key-generation.md)
|
|
603
|
-
|
|
604
|
-
---
|
|
605
|
-
|
|
606
|
-
### 1. 🎯 统一表达式系统 🆕 v1.1.0 - 让聚合查询像SQL一样简单
|
|
607
|
-
|
|
608
|
-
**122个操作符(100% MongoDB支持!新增49个函数)**,让MongoDB聚合查询**像写SQL一样简单**!
|
|
609
|
-
|
|
610
|
-
<table>
|
|
611
|
-
<tr>
|
|
612
|
-
<td width="50%">
|
|
613
|
-
|
|
614
|
-
**🆕 统一表达式语法**
|
|
615
|
-
|
|
616
|
-
```javascript
|
|
617
|
-
const { expr } = require('monsqlize');
|
|
618
|
-
|
|
619
|
-
// ❌ MongoDB原生(繁琐)
|
|
620
|
-
await users.aggregate([
|
|
621
|
-
{
|
|
622
|
-
$project: {
|
|
623
|
-
fullName: {
|
|
624
|
-
$concat: ['$firstName', ' ', '$lastName']
|
|
625
|
-
},
|
|
626
|
-
age: {
|
|
627
|
-
$subtract: [
|
|
628
|
-
{ $year: new Date() },
|
|
629
|
-
{ $year: '$birthDate' }
|
|
630
|
-
]
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
]);
|
|
635
|
-
|
|
636
|
-
// ✅ 统一表达式(简洁)
|
|
637
|
-
await users.aggregate([
|
|
638
|
-
{
|
|
639
|
-
$project: {
|
|
640
|
-
fullName: expr("CONCAT(firstName, ' ', lastName)"),
|
|
641
|
-
age: expr("YEAR(CURRENT_DATE) - YEAR(birthDate)")
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
]);
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
</td>
|
|
648
|
-
<td width="50%">
|
|
649
|
-
|
|
650
|
-
**核心优势**
|
|
651
|
-
|
|
652
|
-
- ✅ **67个操作符** - 覆盖95%使用场景
|
|
653
|
-
- ✅ **类SQL语法** - 易读易写,降低学习成本
|
|
654
|
-
- ✅ **上下文感知** - 自动适配$match/$project/$group
|
|
655
|
-
- ✅ **Lambda表达式** - FILTER/MAP完整支持
|
|
656
|
-
- ✅ **高性能** - LRU缓存,>90%命中率
|
|
657
|
-
- ✅ **100%兼容** - 可与原生语法混用
|
|
658
|
-
|
|
659
|
-
**支持的操作符分类**:
|
|
660
|
-
- 🔹 条件判断 (三元、SWITCH)
|
|
661
|
-
- 🔹 数学计算 (ABS、ROUND、POW等)
|
|
662
|
-
- 🔹 字符串处理 (CONCAT、SPLIT、REPLACE等)
|
|
663
|
-
- 🔹 数组操作 (FILTER、MAP、SIZE等)
|
|
664
|
-
- 🔹 日期处理 (YEAR、MONTH、DAY等)
|
|
665
|
-
- 🔹 类型转换 (TO_INT、TO_STRING等)
|
|
666
|
-
|
|
667
|
-
</td>
|
|
668
|
-
</tr>
|
|
669
|
-
</table>
|
|
670
|
-
|
|
671
|
-
**更多示例**:
|
|
672
|
-
|
|
673
|
-
```javascript
|
|
674
|
-
// 条件判断 - 三元运算符
|
|
675
|
-
expr("score >= 90 ? 'A' : 'B'")
|
|
676
|
-
|
|
677
|
-
// 多分支条件 - SWITCH
|
|
678
|
-
expr("SWITCH(score >= 90, 'A', score >= 80, 'B', score >= 60, 'C', 'F')")
|
|
679
|
-
|
|
680
|
-
// 字符串处理
|
|
681
|
-
expr("UPPER(TRIM(email))")
|
|
682
|
-
expr("SPLIT(tags, ',')")
|
|
683
|
-
|
|
684
|
-
// 数组过滤(Lambda表达式)
|
|
685
|
-
expr("FILTER(items, item, item.price > 100)")
|
|
686
|
-
|
|
687
|
-
// 日期计算
|
|
688
|
-
expr("YEAR(createdAt) === 2024 && MONTH(createdAt) === 12")
|
|
689
|
-
|
|
690
|
-
// 完整聚合查询示例
|
|
691
|
-
await orders.aggregate([
|
|
692
|
-
{
|
|
693
|
-
$project: {
|
|
694
|
-
// 价格计算
|
|
695
|
-
finalPrice: expr("price * (1 - discount / 100)"),
|
|
696
|
-
|
|
697
|
-
// 日期提取
|
|
698
|
-
year: expr("YEAR(createdAt)"),
|
|
699
|
-
month: expr("MONTH(createdAt)"),
|
|
700
|
-
|
|
701
|
-
// 状态分类
|
|
702
|
-
statusLabel: expr("SWITCH(status === 'paid', 'Paid', status === 'pending', 'Pending', 'Cancelled')")
|
|
703
|
-
}
|
|
704
|
-
},
|
|
705
|
-
{
|
|
706
|
-
$group: {
|
|
707
|
-
_id: { year: '$year', month: '$month' },
|
|
708
|
-
totalOrders: expr("COUNT()"),
|
|
709
|
-
totalRevenue: expr("SUM(finalPrice)")
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
]);
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
📖 **完整文档**:[统一表达式系统](./docs/aggregate.md#统一表达式系统) | [67个操作符列表](./docs/aggregate.md#支持的操作符-67个)
|
|
716
|
-
|
|
717
|
-
---
|
|
718
|
-
|
|
719
|
-
### 2. ⚡ 智能缓存系统 - 性能提升 10~100 倍
|
|
720
|
-
|
|
721
|
-
<table>
|
|
722
|
-
<tr>
|
|
723
|
-
<td width="50%">
|
|
724
|
-
|
|
725
|
-
**特性**
|
|
726
|
-
|
|
727
|
-
- ✅ **TTL 过期策略** - 指定缓存时间
|
|
728
|
-
- ✅ **LRU 淘汰策略** - 自动淘汰旧数据
|
|
729
|
-
- ✅ **精准失效 🆕** - 只清除受影响的缓存
|
|
730
|
-
- ✅ **自动失效** - 写操作自动清理缓存
|
|
731
|
-
- ✅ **并发去重** - 相同查询只执行一次
|
|
732
|
-
- ✅ **多层缓存** - 内存 + Redis
|
|
733
|
-
- ✅ **命名空间隔离** - 按集合独立管理
|
|
734
|
-
|
|
735
|
-
</td>
|
|
736
|
-
<td width="50%">
|
|
737
|
-
|
|
738
|
-
**性能提升**
|
|
739
|
-
|
|
740
|
-
| 操作 | 原生驱动 | monSQLize | 提升 |
|
|
741
|
-
|------|---------|-----------|------|
|
|
742
|
-
| 热点查询 | 50ms | 0.5ms | **100x** ⚡ |
|
|
743
|
-
| 复杂聚合 | 200ms | 2ms | **100x** ⚡ |
|
|
744
|
-
| 列表查询 | 30ms | 0.3ms | **100x** ⚡ |
|
|
745
|
-
|
|
746
|
-
</td>
|
|
747
|
-
</tr>
|
|
748
|
-
</table>
|
|
749
|
-
|
|
750
|
-
```javascript
|
|
751
|
-
// 一行代码启用缓存
|
|
752
|
-
const users = await collection.find({ status: 'active' }, { cache: 60000 });
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
### 2. 🔄 事务管理优化 - 减少 30% 数据库访问
|
|
756
|
-
|
|
757
|
-
```javascript
|
|
758
|
-
// 自动管理事务生命周期
|
|
759
|
-
await db.withTransaction(async (tx) => {
|
|
760
|
-
// 只读操作会被优化(不加锁,减少 30% 访问)
|
|
761
|
-
const user = await users.findOne({ _id: userId }, { session: tx.session });
|
|
762
|
-
|
|
763
|
-
// 写操作自动加锁
|
|
764
|
-
await users.updateOne({ _id: userId }, { $inc: { balance: -100 } }, { session: tx.session });
|
|
765
|
-
|
|
766
|
-
// 自动提交 or 回滚
|
|
767
|
-
});
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
### 2.5 🔀 Saga 分布式事务 - 跨服务事务协调 🆕
|
|
771
|
-
|
|
772
|
-
```javascript
|
|
773
|
-
// 定义 Saga(跨服务事务)
|
|
774
|
-
msq.defineSaga({
|
|
775
|
-
name: 'create-order-with-payment',
|
|
776
|
-
steps: [
|
|
777
|
-
{
|
|
778
|
-
name: 'create-order',
|
|
779
|
-
execute: async (ctx) => {
|
|
780
|
-
const order = await createOrder(ctx.data);
|
|
781
|
-
// ✅ 可以保存字符串、对象、数组等任何类型
|
|
782
|
-
ctx.set('order', order); // 保存完整对象
|
|
783
|
-
return order;
|
|
784
|
-
},
|
|
785
|
-
compensate: async (ctx) => {
|
|
786
|
-
const order = ctx.get('order');
|
|
787
|
-
await cancelOrder(order.id);
|
|
788
|
-
}
|
|
789
|
-
},
|
|
790
|
-
{
|
|
791
|
-
name: 'charge-payment',
|
|
792
|
-
execute: async (ctx) => {
|
|
793
|
-
const charge = await stripe.charges.create({...});
|
|
794
|
-
ctx.set('charge', charge); // 保存完整对象
|
|
795
|
-
return charge;
|
|
796
|
-
},
|
|
797
|
-
compensate: async (ctx) => {
|
|
798
|
-
const charge = ctx.get('charge');
|
|
799
|
-
await stripe.refunds.create({ charge: charge.id });
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
]
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
// 执行 Saga(失败自动补偿)
|
|
806
|
-
const result = await msq.executeSaga('create-order-with-payment', data);
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
**Saga 特性**:
|
|
810
|
-
- ✅ 跨服务事务协调
|
|
811
|
-
- ✅ 失败自动补偿(逆序执行)
|
|
812
|
-
- ✅ 支持 Redis 分布式(多进程共享)
|
|
813
|
-
- ✅ 无时间限制(突破 60秒限制)
|
|
814
|
-
- ✅ 详细日志(完整执行追踪)
|
|
815
|
-
|
|
816
|
-
[完整文档](./docs/saga-transaction.md)
|
|
817
|
-
|
|
818
|
-
---
|
|
819
|
-
|
|
820
|
-
#### 🆕 Change Stream 数据同步 (v1.0.9)
|
|
821
|
-
|
|
822
|
-
**实时同步数据到备份库,基于 MongoDB Change Stream**
|
|
823
|
-
|
|
824
|
-
```javascript
|
|
825
|
-
const msq = new MonSQLize({
|
|
826
|
-
type: 'mongodb',
|
|
827
|
-
config: {
|
|
828
|
-
uri: 'mongodb://localhost:27017/main',
|
|
829
|
-
replicaSet: 'rs0' // 🔴 必须:Change Stream 需要 Replica Set
|
|
830
|
-
},
|
|
831
|
-
|
|
832
|
-
// 🆕 同步配置
|
|
833
|
-
sync: {
|
|
834
|
-
enabled: true,
|
|
835
|
-
targets: [
|
|
836
|
-
{
|
|
837
|
-
name: 'backup-main',
|
|
838
|
-
uri: 'mongodb://backup:27017/backup',
|
|
839
|
-
collections: ['users', 'orders']
|
|
840
|
-
}
|
|
841
|
-
]
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
await msq.connect();
|
|
846
|
-
|
|
847
|
-
// 正常使用,自动同步
|
|
848
|
-
await msq.collection('users').insertOne({ name: 'Alice' });
|
|
849
|
-
// ✅ 自动通过 Change Stream 同步到 backup-main
|
|
850
|
-
```
|
|
851
|
-
|
|
852
|
-
**Change Stream 特性**:
|
|
853
|
-
- ✅ 实时同步(延迟 10-500ms)
|
|
854
|
-
- ✅ 断点续传(Resume Token)
|
|
855
|
-
- ✅ 多目标支持(多地容灾)
|
|
856
|
-
- ✅ 数据过滤和转换
|
|
857
|
-
- ✅ 自动重连和健康检查
|
|
858
|
-
- ✅ 主库影响 <2%(异步处理)
|
|
859
|
-
|
|
860
|
-
[完整文档](./docs/sync-backup.md)
|
|
861
|
-
|
|
862
|
-
### 4. 📦 便利方法 - 减少 60~80% 代码
|
|
863
|
-
|
|
864
|
-
<table>
|
|
865
|
-
<tr>
|
|
866
|
-
<td width="50%">
|
|
867
|
-
|
|
868
|
-
**❌ 原生驱动**
|
|
869
|
-
|
|
870
|
-
```javascript
|
|
871
|
-
// 查询单个文档(需要手动转换 ObjectId)
|
|
872
|
-
const { ObjectId } = require('mongodb');
|
|
873
|
-
const user = await users.findOne({
|
|
874
|
-
_id: new ObjectId(userId)
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
// 批量查询(需要手动构建 $in)
|
|
878
|
-
const userList = await users.find({
|
|
879
|
-
_id: { $in: ids.map(id => new ObjectId(id)) }
|
|
880
|
-
}).toArray();
|
|
881
|
-
|
|
882
|
-
// Upsert(需要手动设置选项)
|
|
883
|
-
await users.updateOne(
|
|
884
|
-
{ email: 'alice@example.com' },
|
|
885
|
-
{ $set: { name: 'Alice', age: 30 } },
|
|
886
|
-
{ upsert: true }
|
|
887
|
-
);
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
</td>
|
|
891
|
-
<td width="50%">
|
|
892
|
-
|
|
893
|
-
**✅ monSQLize**
|
|
894
|
-
|
|
895
|
-
```javascript
|
|
896
|
-
// 查询单个文档(自动转换)
|
|
897
|
-
const user = await users.findOneById(userId);
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
// 批量查询(一行搞定)
|
|
903
|
-
const userList = await users.findByIds(ids);
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
// Upsert(语义化)
|
|
909
|
-
await users.upsertOne(
|
|
910
|
-
{ email: 'alice@example.com' },
|
|
911
|
-
{ name: 'Alice', age: 30 }
|
|
912
|
-
);
|
|
913
|
-
```
|
|
914
|
-
|
|
915
|
-
**代码减少 60~80%!**
|
|
916
|
-
|
|
917
|
-
</td>
|
|
918
|
-
</tr>
|
|
919
|
-
</table>
|
|
920
|
-
|
|
921
|
-
**🔥 ObjectId 自动转换** - 告别手动转换
|
|
922
|
-
|
|
923
|
-
```javascript
|
|
924
|
-
// ❌ 原生驱动 - 每次都要转换
|
|
925
|
-
const { ObjectId } = require('mongodb');
|
|
926
|
-
await users.findOne({ _id: new ObjectId(userId) });
|
|
927
|
-
await users.find({ _id: { $in: ids.map(id => new ObjectId(id)) } }).toArray();
|
|
928
|
-
|
|
929
|
-
// ✅ monSQLize - 自动识别并转换
|
|
930
|
-
await users.findOneById(userId); // 自动转换字符串
|
|
931
|
-
await users.findByIds([id1, id2, id3]); // 批量自动转换
|
|
932
|
-
await users.findOne({ _id: userId }); // 查询时也自动转换
|
|
933
|
-
```
|
|
934
|
-
|
|
935
|
-
### 4. 🌐 分布式部署支持
|
|
936
|
-
|
|
937
|
-
```javascript
|
|
938
|
-
// 多实例部署,Redis 自动同步缓存
|
|
939
|
-
const db = new MonSQLize({
|
|
940
|
-
cache: {
|
|
941
|
-
distributed: {
|
|
942
|
-
enabled: true,
|
|
943
|
-
redis: redisInstance // 使用 Redis 广播缓存失效
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
// 实例 A 更新数据
|
|
949
|
-
await users.updateOne({ _id: userId }, { $set: { name: 'Bob' } });
|
|
950
|
-
// ⚡ 实例 B/C/D 的缓存自动失效
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
### 5. 🆕 业务级分布式锁(v1.4.0)
|
|
954
|
-
|
|
955
|
-
```javascript
|
|
956
|
-
// 🔥 解决复杂业务场景的并发问题
|
|
957
|
-
|
|
958
|
-
// 场景1:库存扣减
|
|
959
|
-
await db.withLock(`inventory:${sku}`, async () => {
|
|
960
|
-
const product = await inventory.findOne({ sku });
|
|
961
|
-
const price = calculatePrice(product, user, coupon); // 复杂计算
|
|
962
|
-
if (user.balance < price) throw new Error('余额不足');
|
|
963
|
-
|
|
964
|
-
await inventory.updateOne({ sku }, { $inc: { stock: -1 } });
|
|
965
|
-
await users.updateOne({ userId }, { $inc: { balance: -price } });
|
|
966
|
-
await orders.insertOne({ userId, sku, price });
|
|
967
|
-
});
|
|
968
|
-
|
|
969
|
-
// 场景2:定时任务防重(多实例环境)
|
|
970
|
-
const lock = await db.tryAcquireLock('cron:daily-report');
|
|
971
|
-
if (lock) {
|
|
972
|
-
try {
|
|
973
|
-
await generateDailyReport(); // 只有一个实例执行
|
|
974
|
-
} finally {
|
|
975
|
-
await lock.release();
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
```
|
|
979
|
-
|
|
980
|
-
**特性**:基于 Redis · 自动重试 · TTL 防死锁 · 支持续期 · 降级策略
|
|
981
|
-
|
|
982
|
-
[📖 完整文档](./docs/business-lock.md)
|
|
983
|
-
|
|
984
|
-
### 6. 🚀 高性能批量插入
|
|
985
|
-
|
|
986
|
-
```javascript
|
|
987
|
-
// 批量插入 10 万条数据
|
|
988
|
-
await users.insertBatch(documents, {
|
|
989
|
-
batchSize: 1000, // 每批 1000 条
|
|
990
|
-
retryTimes: 3, // 失败重试 3 次
|
|
991
|
-
onProgress: (stats) => {
|
|
992
|
-
console.log(`进度: ${stats.inserted}/${stats.total}`);
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
```
|
|
996
|
-
|
|
997
|
-
**性能**: 比原生 `insertMany` 快 **10~50 倍** ⚡
|
|
998
|
-
|
|
999
|
-
### 7. 📊 深度分页 - 支持千万级数据
|
|
1000
|
-
|
|
1001
|
-
```javascript
|
|
1002
|
-
// 千万级数据分页(游标分页,性能稳定)
|
|
1003
|
-
const result = await users.findPage({
|
|
1004
|
-
query: { status: 'active' },
|
|
1005
|
-
page: 1000, // 第 1000 页
|
|
1006
|
-
limit: 20,
|
|
1007
|
-
totals: {
|
|
1008
|
-
mode: 'async', // 异步统计总数
|
|
1009
|
-
ttl: 300000 // 缓存 5 分钟
|
|
1010
|
-
}
|
|
1011
|
-
});
|
|
1012
|
-
|
|
1013
|
-
console.log(`总计: ${result.totals.total}, 共 ${result.totals.totalPages} 页`);
|
|
1014
|
-
```
|
|
1015
|
-
|
|
1016
|
-
### 8. 🛠️ 运维监控(开箱即用)
|
|
1017
|
-
|
|
1018
|
-
```javascript
|
|
1019
|
-
// 🆕 慢查询日志持久化存储(v1.3+)
|
|
1020
|
-
const msq = new MonSQLize({
|
|
1021
|
-
type: 'mongodb',
|
|
1022
|
-
config: { uri: 'mongodb://localhost:27017/mydb' },
|
|
1023
|
-
slowQueryMs: 500,
|
|
1024
|
-
slowQueryLog: true // ✅ 零配置启用,自动存储到 admin.slow_query_logs
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
await msq.connect();
|
|
1028
|
-
|
|
1029
|
-
// 查询慢查询日志(支持去重聚合)
|
|
1030
|
-
const logs = await msq.getSlowQueryLogs(
|
|
1031
|
-
{ collection: 'users' },
|
|
1032
|
-
{ sort: { count: -1 }, limit: 10 } // 查询高频慢查询Top10
|
|
1033
|
-
);
|
|
1034
|
-
// [{ queryHash: 'abc123', count: 2400, avgTimeMs: 520, maxTimeMs: 1200, ... }]
|
|
1035
|
-
|
|
1036
|
-
// 自动记录慢查询(原有功能)
|
|
1037
|
-
// [WARN] Slow query { ns: 'mydb.users', duration: 1200ms, query: {...} }
|
|
1038
|
-
|
|
1039
|
-
// 健康检查
|
|
1040
|
-
const health = await db.health();
|
|
1041
|
-
// { status: 'ok', uptime: 3600, connections: 10 }
|
|
1042
|
-
|
|
1043
|
-
// 性能指标
|
|
1044
|
-
const stats = await db.getStats();
|
|
1045
|
-
// { queries: 10000, cacheHits: 9000, hitRate: 0.9 }
|
|
1046
|
-
```
|
|
1047
|
-
|
|
1048
|
-
### 9. 🔐 SSH隧道 - 安全连接内网数据库(v1.3+)
|
|
1049
|
-
|
|
1050
|
-
```javascript
|
|
1051
|
-
// 场景:数据库位于防火墙后,无法直接访问
|
|
1052
|
-
const db = new MonSQLize({
|
|
1053
|
-
type: 'mongodb',
|
|
1054
|
-
config: {
|
|
1055
|
-
// SSH隧道配置
|
|
1056
|
-
ssh: {
|
|
1057
|
-
host: 'bastion.example.com', // SSH服务器(跳板机)
|
|
1058
|
-
port: 22,
|
|
1059
|
-
username: 'deploy',
|
|
1060
|
-
password: 'your-password', // ✅ 支持密码认证
|
|
1061
|
-
// 或使用私钥认证(推荐)
|
|
1062
|
-
// privateKeyPath: '~/.ssh/id_rsa',
|
|
1063
|
-
},
|
|
1064
|
-
// MongoDB连接配置(内网地址,自动从URI解析remoteHost和remotePort)
|
|
1065
|
-
uri: 'mongodb://user:pass@internal-mongo:27017/mydb'
|
|
1066
|
-
}
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
|
-
await db.connect(); // 自动建立SSH隧道
|
|
1070
|
-
// 正常使用MongoDB,无需关心隧道细节
|
|
1071
|
-
const users = db.collection('users');
|
|
1072
|
-
const data = await users.findOne({});
|
|
1073
|
-
await db.close(); // 自动关闭SSH隧道
|
|
1074
|
-
```
|
|
1075
|
-
|
|
1076
|
-
**特性**:
|
|
1077
|
-
- ✅ 支持密码和私钥认证
|
|
1078
|
-
- ✅ 自动管理隧道生命周期
|
|
1079
|
-
- ✅ 完美跨平台(基于ssh2库)
|
|
1080
|
-
- ✅ 开箱即用,零额外配置
|
|
1081
|
-
|
|
1082
|
-
[📖 SSH隧道详细文档](./docs/ssh-tunnel.md)
|
|
1083
|
-
|
|
1084
|
-
---
|
|
1085
|
-
|
|
1086
|
-
### 10. 🔄 ObjectId 跨版本兼容(v1.1.1+)🆕
|
|
1087
|
-
|
|
1088
|
-
解决混用 mongoose 和 monSQLize 时的 BSON 版本冲突问题。
|
|
1089
|
-
|
|
1090
|
-
```javascript
|
|
1091
|
-
// ❌ 问题场景:mongoose (bson@4.x/5.x) + monSQLize (bson@6.x)
|
|
1092
|
-
const dataFromMongoose = await MongooseModel.findOne({ ... }).lean();
|
|
1093
|
-
await msq.collection('orders').insertOne(dataFromMongoose);
|
|
1094
|
-
// 错误:Unsupported BSON version, bson types must be from bson 6.x.x
|
|
1095
|
-
|
|
1096
|
-
// ✅ monSQLize v1.1.1+ 自动处理
|
|
1097
|
-
const dataFromMongoose = await MongooseModel.findOne({ ... }).lean();
|
|
1098
|
-
await msq.collection('orders').insertOne(dataFromMongoose);
|
|
1099
|
-
// 成功:自动将旧版本 ObjectId 转换为 bson@6.x
|
|
1100
|
-
```
|
|
1101
|
-
|
|
1102
|
-
**特性**:
|
|
1103
|
-
- ✅ 自动检测并转换来自其他 BSON 版本的 ObjectId
|
|
1104
|
-
- ✅ 递归处理嵌套对象和数组
|
|
1105
|
-
- ✅ 性能优化:无需转换时零拷贝
|
|
1106
|
-
- ✅ 错误降级:转换失败不影响其他字段
|
|
1107
|
-
- ✅ 完全透明:无需修改业务代码
|
|
1108
|
-
|
|
1109
|
-
**兼容性**:
|
|
1110
|
-
|
|
1111
|
-
| BSON 版本 | mongoose 版本 | 支持状态 |
|
|
1112
|
-
|-----------|--------------|---------|
|
|
1113
|
-
| bson@4.x | mongoose@5.x | ✅ 完全支持 |
|
|
1114
|
-
| bson@5.x | mongoose@6.x | ✅ 完全支持 |
|
|
1115
|
-
| bson@6.x | mongoose@7.x | ✅ 原生支持 |
|
|
1116
|
-
|
|
1117
|
-
[📖 完整文档](./docs/objectid-cross-version.md)
|
|
1118
|
-
|
|
1119
|
-
---
|
|
1120
|
-
|
|
1121
|
-
### 11. 🎯 Model 层 - 像 ORM 一样使用(v1.0.3+)
|
|
1122
|
-
|
|
1123
|
-
monSQLize 提供了一个轻量级的 Model 层,让你可以像使用 ORM 一样定义数据模型,同时保持 MongoDB 的灵活性。
|
|
1124
|
-
|
|
1125
|
-
> **📦 依赖说明**: Model 层基于 `schema-dsl` 库实现 Schema 验证,已随 monsqlize 自动安装。
|
|
1126
|
-
|
|
1127
|
-
```javascript
|
|
1128
|
-
const { Model } = require('monsqlize');
|
|
1129
|
-
|
|
1130
|
-
// 1. 定义 Model(集成 schema-dsl 验证)
|
|
1131
|
-
Model.define('users', {
|
|
1132
|
-
enums: {
|
|
1133
|
-
role: 'admin|user|guest'
|
|
1134
|
-
},
|
|
1135
|
-
schema: function(dsl) {
|
|
1136
|
-
return dsl({
|
|
1137
|
-
username: 'string:3-32!',
|
|
1138
|
-
email: 'email!',
|
|
1139
|
-
role: this.enums.role.default('user'),
|
|
1140
|
-
age: 'number:1-150'
|
|
1141
|
-
});
|
|
1142
|
-
},
|
|
1143
|
-
options: {
|
|
1144
|
-
timestamps: true, // 🆕 v1.0.3: 自动管理 createdAt/updatedAt
|
|
1145
|
-
softDelete: true // 🆕 v1.0.3: 软删除(标记删除,支持恢复)
|
|
1146
|
-
},
|
|
1147
|
-
methods: (model) => ({
|
|
1148
|
-
// 实例方法 - 注入到查询返回的文档对象
|
|
1149
|
-
instance: {
|
|
1150
|
-
isAdmin() {
|
|
1151
|
-
return this.role === 'admin';
|
|
1152
|
-
}
|
|
1153
|
-
},
|
|
1154
|
-
// 静态方法 - 挂载到 Model 实例
|
|
1155
|
-
static: {
|
|
1156
|
-
async findByEmail(email) {
|
|
1157
|
-
return await model.findOne({ email });
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}),
|
|
1161
|
-
hooks: (model) => ({
|
|
1162
|
-
// 生命周期钩子
|
|
1163
|
-
insert: {
|
|
1164
|
-
before: (ctx, docs) => {
|
|
1165
|
-
// 自动添加时间戳
|
|
1166
|
-
return { ...docs, createdAt: new Date() };
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
}),
|
|
1170
|
-
indexes: [
|
|
1171
|
-
{ key: { username: 1 }, unique: true },
|
|
1172
|
-
{ key: { email: 1 }, unique: true }
|
|
1173
|
-
]
|
|
1174
|
-
});
|
|
1175
|
-
|
|
1176
|
-
// 2. 使用 Model
|
|
1177
|
-
const db = new MonSQLize({ /* ... */ });
|
|
1178
|
-
await db.connect();
|
|
1179
|
-
|
|
1180
|
-
const User = db.model('users');
|
|
1181
|
-
|
|
1182
|
-
// 自动 Schema 验证
|
|
1183
|
-
const user = await User.insertOne({
|
|
1184
|
-
username: 'john',
|
|
1185
|
-
email: 'john@example.com',
|
|
1186
|
-
age: 25
|
|
1187
|
-
}); // ✅ 验证通过
|
|
1188
|
-
|
|
1189
|
-
// 使用实例方法
|
|
1190
|
-
const admin = await User.findOne({ username: 'admin' });
|
|
1191
|
-
console.log(admin.isAdmin()); // true
|
|
1192
|
-
|
|
1193
|
-
// 使用静态方法
|
|
1194
|
-
const user = await User.findByEmail('john@example.com');
|
|
1195
|
-
|
|
1196
|
-
// 软删除(标记删除,可恢复)
|
|
1197
|
-
await User.deleteOne({ _id: user._id });
|
|
1198
|
-
|
|
1199
|
-
// 查询(自动过滤已删除)
|
|
1200
|
-
const users = await User.find({}); // 不包含已删除用户
|
|
1201
|
-
|
|
1202
|
-
// 查询包含已删除
|
|
1203
|
-
const allUsers = await User.findWithDeleted({});
|
|
1204
|
-
|
|
1205
|
-
// 恢复已删除
|
|
1206
|
-
await User.restore({ _id: user._id });
|
|
1207
|
-
```
|
|
1208
|
-
|
|
1209
|
-
**特性**:
|
|
1210
|
-
- ✅ Schema 验证(集成 schema-dsl)
|
|
1211
|
-
- ✅ 自定义方法(instance + static)
|
|
1212
|
-
- ✅ 生命周期钩子(before/after)
|
|
1213
|
-
- ✅ 索引自动创建
|
|
1214
|
-
- ✅ 自动时间戳(v1.0.3+)
|
|
1215
|
-
- ✅ 软删除(v1.0.3+)
|
|
1216
|
-
- ✅ 乐观锁版本控制(v1.0.3+)
|
|
1217
|
-
- ✅ **关系定义和 populate(v1.2.0+)** 🆕
|
|
1218
|
-
- ✅ TypeScript 类型支持
|
|
1219
|
-
|
|
1220
|
-
#### 关系定义和 populate(v1.2.0+)🆕
|
|
1221
|
-
|
|
1222
|
-
轻松处理集合之间的关联关系,支持 one-to-one 和 one-to-many。
|
|
1223
|
-
|
|
1224
|
-
```javascript
|
|
1225
|
-
// 1. 定义关系
|
|
1226
|
-
Model.define('users', {
|
|
1227
|
-
schema: (dsl) => dsl({
|
|
1228
|
-
username: 'string!',
|
|
1229
|
-
profileId: 'objectId'
|
|
1230
|
-
}),
|
|
1231
|
-
relations: {
|
|
1232
|
-
// one-to-one: 用户 → 个人资料
|
|
1233
|
-
profile: {
|
|
1234
|
-
from: 'profiles', // 集合名
|
|
1235
|
-
localField: 'profileId', // 本地字段
|
|
1236
|
-
foreignField: '_id', // 外部字段
|
|
1237
|
-
single: true // 返回类型
|
|
1238
|
-
},
|
|
1239
|
-
// one-to-many: 用户 → 文章列表
|
|
1240
|
-
posts: {
|
|
1241
|
-
from: 'posts',
|
|
1242
|
-
localField: '_id',
|
|
1243
|
-
foreignField: 'authorId',
|
|
1244
|
-
single: false // 返回数组
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1248
|
-
|
|
1249
|
-
// 2. 使用 populate
|
|
1250
|
-
const user = await User.findOne({ username: 'john' })
|
|
1251
|
-
.populate('profile') // 填充 profile
|
|
1252
|
-
.populate('posts', { // 填充 posts
|
|
1253
|
-
select: 'title content', // 只选择部分字段
|
|
1254
|
-
match: { status: 'published' }, // 额外查询条件
|
|
1255
|
-
sort: { createdAt: -1 }, // 排序
|
|
1256
|
-
limit: 10 // 限制数量
|
|
1257
|
-
});
|
|
1258
|
-
|
|
1259
|
-
// 3. 结果
|
|
1260
|
-
{
|
|
1261
|
-
_id: '...',
|
|
1262
|
-
username: 'john',
|
|
1263
|
-
profileId: '...',
|
|
1264
|
-
profile: { // ← 自动填充
|
|
1265
|
-
_id: '...',
|
|
1266
|
-
bio: 'Software Engineer',
|
|
1267
|
-
avatar: 'https://...'
|
|
1268
|
-
},
|
|
1269
|
-
posts: [ // ← 自动填充
|
|
1270
|
-
{ _id: '...', title: 'Post 1', content: '...' },
|
|
1271
|
-
{ _id: '...', title: 'Post 2', content: '...' }
|
|
1272
|
-
]
|
|
1273
|
-
}
|
|
1274
|
-
```
|
|
1275
|
-
|
|
1276
|
-
**支持的查询方法**(全部 6 个):
|
|
1277
|
-
- ✅ `find().populate()` - 批量查询
|
|
1278
|
-
- ✅ `findOne().populate()` - 单文档查询
|
|
1279
|
-
- ✅ `findByIds().populate()` - 批量 ID 查询
|
|
1280
|
-
- ✅ `findOneById().populate()` - 单 ID 查询
|
|
1281
|
-
- ✅ `findAndCount().populate()` - 带计数查询
|
|
1282
|
-
- ✅ `findPage().populate()` - 分页查询
|
|
1283
|
-
|
|
1284
|
-
**特点**:
|
|
1285
|
-
- ✅ 极简配置(只需 4 个字段)
|
|
1286
|
-
- ✅ 接近 MongoDB 原生(直接对应 `$lookup`)
|
|
1287
|
-
- ✅ 批量查询优化(避免 N+1 问题)
|
|
1288
|
-
- ✅ 支持链式调用
|
|
1289
|
-
- ✅ 丰富的 populate 选项(select/sort/limit/skip/match)
|
|
1290
|
-
|
|
1291
|
-
[📖 Relations 详细文档](./docs/model/relations.md)
|
|
1292
|
-
|
|
1293
|
-
**注意**:需要安装 `schema-dsl` 依赖:
|
|
1294
|
-
```bash
|
|
1295
|
-
npm install schema-dsl
|
|
1296
|
-
```
|
|
1297
|
-
|
|
1298
|
-
#### 热重载支持(v1.1.7+)🆕
|
|
1299
|
-
|
|
1300
|
-
在开发模式下,无需重启进程即可更新 Model 定义。
|
|
1301
|
-
|
|
1302
|
-
```javascript
|
|
1303
|
-
const { Model } = require('monsqlize');
|
|
1304
|
-
|
|
1305
|
-
// 注销 Model 定义(返回 boolean)
|
|
1306
|
-
Model.undefine('users'); // true — 成功注销
|
|
1307
|
-
Model.undefine('nonexistent'); // false — 不存在时不抛错
|
|
1308
|
-
|
|
1309
|
-
// 替换 Model 定义(undefine + define 的组合)
|
|
1310
|
-
Model.redefine('users', {
|
|
1311
|
-
schema: (dsl) => dsl({ username: 'string!', email: 'email!' })
|
|
1312
|
-
});
|
|
1313
|
-
|
|
1314
|
-
// 批量热重载(重新加载所有 model 文件)
|
|
1315
|
-
await msq._loadModels({ reload: true });
|
|
1316
|
-
```
|
|
1317
|
-
|
|
1318
|
-
**注意事项**:
|
|
1319
|
-
- `redefine()` 若新定义校验失败,旧定义**已被移除**(不会回滚),调用方需 try/catch
|
|
1320
|
-
- 已实例化的 `ModelInstance` 不受影响,热重载后应通过 `db.model()` 重新获取实例
|
|
1321
|
-
|
|
1322
|
-
[📖 Model 层详细文档](./docs/model.md)
|
|
1323
|
-
|
|
1324
|
-
---
|
|
1325
|
-
|
|
1326
|
-
## � 进阶功能
|
|
1327
|
-
|
|
1328
|
-
### 1. Change Streams - 实时监听数据变更 ⭐
|
|
1329
|
-
|
|
1330
|
-
```javascript
|
|
1331
|
-
// 实时监听订单变化
|
|
1332
|
-
const watcher = orders.watch([
|
|
1333
|
-
{ $match: { 'fullDocument.status': 'pending' } }
|
|
1334
|
-
]);
|
|
1335
|
-
|
|
1336
|
-
watcher.on('change', (change) => {
|
|
1337
|
-
console.log('新订单:', change.fullDocument);
|
|
1338
|
-
// 触发通知、更新统计、失效缓存等
|
|
1339
|
-
});
|
|
1340
|
-
|
|
1341
|
-
// ✅ 自动处理:重连、错误恢复、缓存失效
|
|
1342
|
-
```
|
|
1343
|
-
|
|
1344
|
-
**特性**: 支持聚合管道过滤 · 断点续传 · 自动失效相关缓存
|
|
1345
|
-
|
|
1346
|
-
[📖 完整文档](./docs/watch.md) | [示例代码](./examples/watch.examples.js)
|
|
1347
|
-
|
|
1348
|
-
---
|
|
1349
|
-
|
|
1350
|
-
### 2. Count 队列控制 - 高并发优化 ⭐
|
|
1351
|
-
|
|
1352
|
-
```javascript
|
|
1353
|
-
// 高并发场景:100 个用户同时请求分页
|
|
1354
|
-
const db = new MonSQLize({
|
|
1355
|
-
countQueue: {
|
|
1356
|
-
enabled: true, // 默认启用
|
|
1357
|
-
concurrency: 8 // 同时最多 8 个 count
|
|
1358
|
-
}
|
|
1359
|
-
});
|
|
1360
|
-
|
|
1361
|
-
// ✅ 自动队列控制,防止 count 拖垮数据库
|
|
1362
|
-
const result = await users.findPage({
|
|
1363
|
-
query: { status: 'active' },
|
|
1364
|
-
totals: { mode: 'async' } // 自动应用队列
|
|
1365
|
-
});
|
|
1366
|
-
```
|
|
1367
|
-
|
|
1368
|
-
**效果**: 数据库 CPU 从 100% → 30% · 其他查询不再超时
|
|
1369
|
-
|
|
1370
|
-
[📖 完整文档](./docs/count-queue.md)
|
|
1371
|
-
|
|
1372
|
-
---
|
|
1373
|
-
|
|
1374
|
-
### 3. 链式调用 API - 优雅的查询构建 ⭐
|
|
1375
|
-
|
|
1376
|
-
```javascript
|
|
1377
|
-
// jQuery 风格的链式调用
|
|
1378
|
-
const result = await users
|
|
1379
|
-
.find()
|
|
1380
|
-
.filter({ age: { $gte: 18 } })
|
|
1381
|
-
.sort({ createdAt: -1 })
|
|
1382
|
-
.limit(10)
|
|
1383
|
-
.cache(60000)
|
|
1384
|
-
.exec();
|
|
1385
|
-
|
|
1386
|
-
// ✅ 代码更清晰、可读性更强
|
|
1387
|
-
```
|
|
1388
|
-
|
|
1389
|
-
[📖 完整文档](./docs/chaining-api.md) | [链式方法参考](./docs/chaining-methods.md)
|
|
1390
|
-
|
|
1391
|
-
---
|
|
1392
|
-
|
|
1393
|
-
### 4. Model 层乐观锁 - 防止并发修改冲突
|
|
1394
|
-
|
|
1395
|
-
```javascript
|
|
1396
|
-
// 启用版本控制
|
|
1397
|
-
Model.define('products', {
|
|
1398
|
-
schema: (dsl) => dsl({ name: 'string!', stock: 'number!' }),
|
|
1399
|
-
options: { optimisticLock: true }
|
|
1400
|
-
});
|
|
1401
|
-
|
|
1402
|
-
// 自动版本检查和更新
|
|
1403
|
-
await Product.updateOne(
|
|
1404
|
-
{ _id: productId, __v: 1 }, // 要求版本为 1
|
|
1405
|
-
{ $inc: { stock: -1 }, $inc: { __v: 1 } } // 自动递增版本
|
|
1406
|
-
);
|
|
1407
|
-
// ❌ 如果版本不匹配(被其他请求修改),更新失败
|
|
1408
|
-
```
|
|
1409
|
-
|
|
1410
|
-
[📖 Model 层文档](./docs/model.md)
|
|
1411
|
-
|
|
1412
|
-
---
|
|
1413
|
-
|
|
1414
|
-
### 5. ES Module 支持 - 现代 JavaScript
|
|
1415
|
-
|
|
1416
|
-
```javascript
|
|
1417
|
-
// ✅ 支持 import/export
|
|
1418
|
-
import MonSQLize from 'monsqlize';
|
|
1419
|
-
|
|
1420
|
-
const db = new MonSQLize({ /* ... */ });
|
|
1421
|
-
await db.connect();
|
|
1422
|
-
|
|
1423
|
-
// 🎯 完美支持 TypeScript
|
|
1424
|
-
import type { Collection, MonSQLizeConfig } from 'monsqlize';
|
|
1425
|
-
```
|
|
1426
|
-
|
|
1427
|
-
[📖 ESM 文档](./docs/esm-support.md)
|
|
1428
|
-
|
|
1429
|
-
---
|
|
1430
|
-
|
|
1431
|
-
## �📊 性能测试报告
|
|
1432
|
-
|
|
1433
|
-
### 测试环境
|
|
1434
|
-
|
|
1435
|
-
- **CPU**: Intel i7-9700K
|
|
1436
|
-
- **内存**: 16GB
|
|
1437
|
-
- **数据库**: MongoDB 5.0
|
|
1438
|
-
- **数据量**: 100 万条
|
|
1439
|
-
|
|
1440
|
-
### 查询性能对比
|
|
1441
|
-
|
|
1442
|
-
| 场景 | 原生驱动 | monSQLize (缓存) | 提升倍数 |
|
|
1443
|
-
|------|---------|------------------|---------|
|
|
1444
|
-
| 热点查询 (findOne) | 10ms | 0.1ms | **100x** ⚡ |
|
|
1445
|
-
| 列表查询 (find) | 50ms | 0.5ms | **100x** ⚡ |
|
|
1446
|
-
| 复杂聚合 (aggregate) | 200ms | 2ms | **100x** ⚡ |
|
|
1447
|
-
| 批量插入 (10万条) | 30s | 1.2s | **25x** ⚡ |
|
|
1448
|
-
|
|
1449
|
-
### 缓存命中率
|
|
1450
|
-
|
|
1451
|
-
- **电商场景**: 85% (商品/用户查询)
|
|
1452
|
-
- **内容平台**: 75% (文章/评论查询)
|
|
1453
|
-
- **社交应用**: 80% (个人资料/动态)
|
|
1454
|
-
|
|
1455
|
-
**结论**: 在真实业务场景中,缓存命中率通常在 **70~90%**,性能提升 **10~100 倍**。
|
|
1456
|
-
|
|
1457
|
-
---
|
|
1458
|
-
|
|
1459
|
-
## 🎨 完整功能清单
|
|
1460
|
-
|
|
1461
|
-
<table>
|
|
1462
|
-
<tr>
|
|
1463
|
-
<td width="33%">
|
|
1464
|
-
|
|
1465
|
-
### 📦 MongoDB 原生功能
|
|
1466
|
-
|
|
1467
|
-
✅ **CRUD 操作**
|
|
1468
|
-
- [find](./docs/find.md) / [findOne](./docs/findOne.md)
|
|
1469
|
-
- [insertOne](./docs/insert-one.md) / [insertMany](./docs/insert-many.md)
|
|
1470
|
-
- [updateOne](./docs/update-one.md) / [updateMany](./docs/update-many.md) ⭐ (支持聚合管道 v1.0.8+)
|
|
1471
|
-
- [deleteOne](./docs/delete-one.md) / [deleteMany](./docs/delete-many.md)
|
|
1472
|
-
- [replaceOne](./docs/replace-one.md)
|
|
1473
|
-
- [findOneAndUpdate](./docs/find-one-and-update.md)
|
|
1474
|
-
- [findOneAndReplace](./docs/find-one-and-replace.md)
|
|
1475
|
-
- [findOneAndDelete](./docs/find-one-and-delete.md)
|
|
1476
|
-
|
|
1477
|
-
✅ **聚合 & 查询**
|
|
1478
|
-
- [aggregate](./docs/aggregate.md)
|
|
1479
|
-
- [count](./docs/count.md) / [distinct](./docs/distinct.md)
|
|
1480
|
-
- [watch (Change Streams)](./docs/watch.md)
|
|
1481
|
-
- [explain](./docs/explain.md)
|
|
1482
|
-
|
|
1483
|
-
✅ **索引管理**
|
|
1484
|
-
- createIndex / createIndexes
|
|
1485
|
-
- listIndexes
|
|
1486
|
-
- dropIndex / dropIndexes
|
|
1487
|
-
|
|
1488
|
-
✅ **[事务支持](./docs/transaction.md)**
|
|
1489
|
-
- withTransaction
|
|
1490
|
-
- startTransaction
|
|
1491
|
-
|
|
1492
|
-
</td>
|
|
1493
|
-
<td width="33%">
|
|
1494
|
-
|
|
1495
|
-
### 🚀 增强功能
|
|
1496
|
-
|
|
1497
|
-
✅ **[企业级多连接池](./docs/multi-pool.md)** (v1.0.8+)
|
|
1498
|
-
- ConnectionPoolManager
|
|
1499
|
-
- 5种智能选择策略
|
|
1500
|
-
- 实时健康检查
|
|
1501
|
-
- 自动故障转移
|
|
1502
|
-
- 完整统计收集
|
|
1503
|
-
|
|
1504
|
-
✅ **[Saga 分布式事务](./docs/saga-transaction.md)** (v1.1.0 计划)
|
|
1505
|
-
- 跨服务事务(设计完成)
|
|
1506
|
-
- 自动补偿机制(设计完成)
|
|
1507
|
-
- 状态跟踪(设计完成)
|
|
1508
|
-
- 超时和重试(设计完成)
|
|
1509
|
-
|
|
1510
|
-
✅ **[智能缓存](./docs/cache.md)**
|
|
1511
|
-
- TTL 过期策略
|
|
1512
|
-
- LRU 淘汰策略
|
|
1513
|
-
- 自动失效机制
|
|
1514
|
-
- 并发去重
|
|
1515
|
-
- [多层缓存 (内存+Redis)](./docs/cache-implementation.md)
|
|
1516
|
-
|
|
1517
|
-
✅ **便利方法**
|
|
1518
|
-
- [findOneById](./docs/find-one-by-id.md)
|
|
1519
|
-
- [findByIds](./docs/find-by-ids.md)
|
|
1520
|
-
- [upsertOne](./docs/upsert-one.md)
|
|
1521
|
-
- [incrementOne](./docs/increment-one.md)
|
|
1522
|
-
- [findAndCount](./docs/find-and-count.md)
|
|
1523
|
-
|
|
1524
|
-
✅ **性能优化**
|
|
1525
|
-
- [insertBatch](./docs/insertBatch.md) - 批量插入优化
|
|
1526
|
-
- [deleteBatch](./docs/deleteBatch.md) - 批量删除(流式+进度监控)
|
|
1527
|
-
- [updateBatch](./docs/updateBatch.md) - 批量更新(流式+进度监控)
|
|
1528
|
-
- 只读事务优化
|
|
1529
|
-
- [Count 队列控制](./docs/count-queue.md)
|
|
1530
|
-
- 连接池管理
|
|
1531
|
-
|
|
1532
|
-
✅ **[分布式支持](./docs/distributed-deployment.md)**
|
|
1533
|
-
- Redis 广播缓存失效
|
|
1534
|
-
- [分布式锁](./docs/business-lock.md)
|
|
1535
|
-
- 多实例一致性
|
|
1536
|
-
|
|
1537
|
-
</td>
|
|
1538
|
-
<td width="33%">
|
|
1539
|
-
|
|
1540
|
-
### 🛠️ 企业级特性
|
|
1541
|
-
|
|
1542
|
-
✅ **运维监控**
|
|
1543
|
-
- [慢查询日志](./docs/slow-query-log.md)(支持持久化存储)🆕
|
|
1544
|
-
- 性能指标统计
|
|
1545
|
-
- 健康检查
|
|
1546
|
-
- 缓存命中率监控
|
|
1547
|
-
|
|
1548
|
-
✅ **[深度分页](./docs/findPage.md)**
|
|
1549
|
-
- 游标分页
|
|
1550
|
-
- 异步总数统计
|
|
1551
|
-
- [书签管理](./docs/bookmarks.md)
|
|
1552
|
-
- 跳页优化
|
|
1553
|
-
|
|
1554
|
-
✅ **数据库管理**
|
|
1555
|
-
- 跨库访问
|
|
1556
|
-
- [Schema 验证](./docs/model.md)
|
|
1557
|
-
- [集合管理](./docs/collection-management.md)
|
|
1558
|
-
- 数据库命令
|
|
1559
|
-
|
|
1560
|
-
✅ **开发体验**
|
|
1561
|
-
- TypeScript 支持
|
|
1562
|
-
- [链式调用 API](./docs/chaining-api.md) ⭐
|
|
1563
|
-
- ESM/CommonJS 双模式
|
|
1564
|
-
- [ObjectId 自动转换](./docs/objectid-auto-convert.md) ⭐
|
|
1565
|
-
- 77% 测试覆盖率
|
|
1566
|
-
|
|
1567
|
-
</td>
|
|
1568
|
-
</tr>
|
|
1569
|
-
</table>
|
|
1570
|
-
|
|
1571
|
-
---
|
|
1572
|
-
|
|
1573
|
-
## 🆚 与 MongoDB 原生驱动对比
|
|
1574
|
-
|
|
1575
|
-
<table>
|
|
1576
|
-
<tr>
|
|
1577
|
-
<th width="25%">特性</th>
|
|
1578
|
-
<th width="25%">MongoDB 原生</th>
|
|
1579
|
-
<th width="50%"><strong>monSQLize</strong></th>
|
|
1580
|
-
</tr>
|
|
1581
|
-
<tr>
|
|
1582
|
-
<td><strong>API 兼容性</strong></td>
|
|
1583
|
-
<td>✅ 原生</td>
|
|
1584
|
-
<td>✅ 100% 兼容原生,无需学习新 API</td>
|
|
1585
|
-
</tr>
|
|
1586
|
-
<tr>
|
|
1587
|
-
<td><strong>智能缓存</strong></td>
|
|
1588
|
-
<td>❌ 需要自己实现</td>
|
|
1589
|
-
<td>✅ 内置 TTL/LRU,开箱即用,10~100倍提升</td>
|
|
1590
|
-
</tr>
|
|
1591
|
-
<tr>
|
|
1592
|
-
<td><strong>性能</strong></td>
|
|
1593
|
-
<td>⭐⭐⭐ 基准性能</td>
|
|
1594
|
-
<td>⭐⭐⭐⭐⭐ 缓存命中时性能提升 10~100 倍</td>
|
|
1595
|
-
</tr>
|
|
1596
|
-
<tr>
|
|
1597
|
-
<td><strong>事务支持</strong></td>
|
|
1598
|
-
<td>⭐⭐ 需要手动管理</td>
|
|
1599
|
-
<td>⭐⭐⭐⭐⭐ 自动管理生命周期,优化只读操作</td>
|
|
1600
|
-
</tr>
|
|
1601
|
-
<tr>
|
|
1602
|
-
<td><strong>分布式部署</strong></td>
|
|
1603
|
-
<td>❌ 缓存不一致</td>
|
|
1604
|
-
<td>✅ Redis 广播自动同步,保证一致性</td>
|
|
1605
|
-
</tr>
|
|
1606
|
-
<tr>
|
|
1607
|
-
<td><strong>便利方法</strong></td>
|
|
1608
|
-
<td>❌ 需要自己封装</td>
|
|
1609
|
-
<td>✅ findOneById、findByIds、upsertOne 等</td>
|
|
1610
|
-
</tr>
|
|
1611
|
-
<tr>
|
|
1612
|
-
<td><strong>运维监控</strong></td>
|
|
1613
|
-
<td>⚠️ 需要额外配置</td>
|
|
1614
|
-
<td>✅ 慢查询日志、性能统计,开箱即用</td>
|
|
1615
|
-
</tr>
|
|
1616
|
-
<tr>
|
|
1617
|
-
<td><strong>学习成本</strong></td>
|
|
1618
|
-
<td>⭐⭐⭐ MongoDB 语法</td>
|
|
1619
|
-
<td>⭐ 零学习成本,API 完全一致</td>
|
|
1620
|
-
</tr>
|
|
1621
|
-
<tr>
|
|
1622
|
-
<td><strong>迁移成本</strong></td>
|
|
1623
|
-
<td>-</td>
|
|
1624
|
-
<td>⭐ 只需修改初始化代码,业务代码不变</td>
|
|
1625
|
-
</tr>
|
|
1626
|
-
</table>
|
|
1627
|
-
|
|
1628
|
-
### 📌 何时选择 monSQLize
|
|
1629
|
-
|
|
1630
|
-
✅ **适合场景**:
|
|
1631
|
-
- 高并发读取场景(商品详情、用户信息)
|
|
1632
|
-
- 需要缓存但不想自己实现
|
|
1633
|
-
- 多实例部署需要缓存一致性
|
|
1634
|
-
- 希望零学习成本提升性能
|
|
1635
|
-
|
|
1636
|
-
⚠️ **不适合场景**:
|
|
1637
|
-
- 纯写入应用(缓存作用有限)
|
|
1638
|
-
- 实时性要求极高(每次必查最新)
|
|
1639
|
-
- 简单应用,流量不大(原生驱动足够)
|
|
1640
|
-
|
|
1641
|
-
---
|
|
1642
|
-
|
|
1643
|
-
## 🚀 快速迁移指南
|
|
1644
|
-
|
|
1645
|
-
### 从 MongoDB 原生驱动迁移
|
|
1646
|
-
|
|
1647
|
-
```javascript
|
|
1648
|
-
// ❌ 原来的代码
|
|
1649
|
-
const { MongoClient } = require('mongodb');
|
|
1650
|
-
const client = await MongoClient.connect('mongodb://localhost:27017');
|
|
1651
|
-
const db = client.db('mydb');
|
|
1652
|
-
const users = db.collection('users');
|
|
1653
|
-
|
|
1654
|
-
// ✅ 迁移后的代码(只需改 3 行)
|
|
1655
|
-
const MonSQLize = require('monsqlize'); // 1. 引入 monSQLize
|
|
1656
|
-
const db = new MonSQLize({ // 2. 修改初始化
|
|
1657
|
-
type: 'mongodb',
|
|
1658
|
-
config: { uri: 'mongodb://localhost:27017/mydb' },
|
|
1659
|
-
cache: { enabled: true } // 3. 启用缓存
|
|
1660
|
-
});
|
|
1661
|
-
await db.connect();
|
|
1662
|
-
const users = db.collection('users');
|
|
1663
|
-
|
|
1664
|
-
// 🎉 后续所有代码不需要改动,性能提升 10~100 倍!
|
|
1665
|
-
const user = await users.findOne({ email }); // 完全一样的 API
|
|
1666
|
-
```
|
|
1667
|
-
|
|
1668
|
-
### 渐进式迁移
|
|
1669
|
-
|
|
1670
|
-
```javascript
|
|
1671
|
-
// ✅ 可以混用原生驱动和 monSQLize
|
|
1672
|
-
const nativeClient = await MongoClient.connect('...');
|
|
1673
|
-
const monsqlize = new MonSQLize({ cache: { enabled: true } });
|
|
1674
|
-
|
|
1675
|
-
// 性能敏感的查询用 monSQLize(启用缓存)
|
|
1676
|
-
const hotData = await monsqlize.collection('products').find({}, { cache: 60000 });
|
|
1677
|
-
|
|
1678
|
-
// 简单查询用原生驱动
|
|
1679
|
-
const coldData = await nativeClient.db('mydb').collection('logs').find({});
|
|
1680
|
-
```
|
|
1681
|
-
|
|
1682
|
-
---
|
|
1683
|
-
|
|
1684
|
-
## 📖 完整文档
|
|
1685
|
-
|
|
1686
|
-
### 核心文档
|
|
1687
|
-
|
|
1688
|
-
- 📖 [完整 API 文档索引](./docs/INDEX.md)
|
|
1689
|
-
- 📖 [MongoDB 原生 vs monSQLize 对比](./docs/mongodb-native-vs-extensions.md)
|
|
1690
|
-
- 📖 [事务使用指南](./docs/transaction.md)
|
|
1691
|
-
- 📖 [业务级分布式锁](./docs/business-lock.md) 🆕 v1.4.0
|
|
1692
|
-
- 📖 [SSH隧道使用指南](./docs/ssh-tunnel.md) 🆕 v1.3+
|
|
1693
|
-
- 📖 [分布式部署指南](./docs/distributed-deployment.md)
|
|
1694
|
-
- 📖 [性能优化指南](./docs/transaction-optimizations.md)
|
|
1695
|
-
|
|
1696
|
-
### 功能文档
|
|
1697
|
-
|
|
1698
|
-
**CRUD 操作**:
|
|
1699
|
-
- [find](./docs/find.md) | [findOne](./docs/findOne.md) | [findPage](./docs/findPage.md)
|
|
1700
|
-
- [insertOne](./docs/insert-one.md) | [insertMany](./docs/insert-many.md) | [insertBatch](./docs/insertBatch.md)
|
|
1701
|
-
- [updateOne](./docs/update-one.md) | [updateMany](./docs/update-many.md) | [updateBatch](./docs/updateBatch.md) | [replaceOne](./docs/replace-one.md)
|
|
1702
|
-
- [deleteOne](./docs/delete-one.md) | [deleteMany](./docs/delete-many.md) | [deleteBatch](./docs/deleteBatch.md)
|
|
1703
|
-
|
|
1704
|
-
**Model 层**:
|
|
1705
|
-
- [Model API 文档](./docs/model.md) - Schema 验证、自定义方法、生命周期钩子
|
|
1706
|
-
|
|
1707
|
-
**便利方法**:
|
|
1708
|
-
- [findOneById](./docs/find-one-by-id.md) | [findByIds](./docs/find-by-ids.md)
|
|
1709
|
-
- [upsertOne](./docs/upsert-one.md) | [incrementOne](./docs/increment-one.md) | [findAndCount](./docs/find-and-count.md)
|
|
1710
|
-
|
|
1711
|
-
**其他功能**:
|
|
1712
|
-
- [索引管理](./docs/create-index.md) | [聚合查询](./docs/aggregate.md)
|
|
1713
|
-
- [缓存系统](./docs/cache.md) | [链式调用](./docs/chaining-api.md)
|
|
1714
|
-
|
|
1715
|
-
### 示例代码
|
|
1716
|
-
|
|
1717
|
-
- 📁 [完整示例代码目录](./examples/) - 50+ 可运行示例
|
|
1718
|
-
|
|
1719
|
-
---
|
|
1720
|
-
|
|
1721
|
-
## 🌍 兼容性
|
|
1722
|
-
|
|
1723
|
-
| 环境 | 支持版本 |
|
|
1724
|
-
|------|---------|
|
|
1725
|
-
| **Node.js** | 16.x, 18.x, 20.x, 21.x |
|
|
1726
|
-
| **MongoDB** | 4.4+, 5.x, 6.x, 7.x |
|
|
1727
|
-
| **MongoDB Driver** | 4.x, 5.x, 6.x, 7.x |
|
|
1728
|
-
| **模块系统** | CommonJS, ESM |
|
|
1729
|
-
|
|
1730
|
-
[查看完整兼容性矩阵](./docs/COMPATIBILITY.md)
|
|
1731
|
-
|
|
1732
|
-
---
|
|
1733
|
-
|
|
1734
|
-
## 🗺️ 产品路线图
|
|
1735
|
-
|
|
1736
|
-
### ✅ v1.4 (当前版本)
|
|
1737
|
-
|
|
1738
|
-
- ✅ 业务级分布式锁
|
|
1739
|
-
- ✅ 智能缓存系统
|
|
1740
|
-
- ✅ 事务优化
|
|
1741
|
-
- ✅ 便利方法
|
|
1742
|
-
- ✅ 分布式支持
|
|
1743
|
-
- ✅ Model 层(v1.0.3)- Schema 验证、自定义方法、生命周期钩子
|
|
1744
|
-
|
|
1745
|
-
### 🚧 v1.5 (计划中)
|
|
1746
|
-
|
|
1747
|
-
- 🔄 查询分析器
|
|
1748
|
-
- 🔄 自动索引建议
|
|
1749
|
-
- 🔄 数据迁移工具
|
|
1750
|
-
- 🔄 GraphQL 支持
|
|
1751
|
-
- 🔄 Model 关系(relations)完善
|
|
1752
|
-
|
|
1753
|
-
### 🔮 v2.0 (未来)
|
|
1754
|
-
|
|
1755
|
-
- 🔮 统一 API 支持 MySQL
|
|
1756
|
-
- 🔮 统一 API 支持 PostgreSQL
|
|
1757
|
-
- 🔮 完整 ORM 功能
|
|
1758
|
-
- 🔮 数据同步中间件
|
|
1759
|
-
|
|
1760
|
-
---
|
|
1761
|
-
|
|
1762
|
-
## 🤝 贡献指南
|
|
1763
|
-
|
|
1764
|
-
我们欢迎所有形式的贡献!
|
|
1765
|
-
|
|
1766
|
-
- 🐛 [提交 Bug](https://github.com/vextjs/monSQLize/issues)
|
|
1767
|
-
- 💡 [提出新功能](https://github.com/vextjs/monSQLize/issues)
|
|
1768
|
-
- 📖 [改进文档](https://github.com/vextjs/monSQLize/pulls)
|
|
1769
|
-
- 💻 [提交代码](https://github.com/vextjs/monSQLize/pulls)
|
|
1770
|
-
|
|
1771
|
-
### 开发
|
|
1772
|
-
|
|
1773
|
-
```bash
|
|
1774
|
-
# 克隆仓库
|
|
1775
|
-
git clone https://github.com/vextjs/monSQLize.git
|
|
1776
|
-
cd monSQLize
|
|
1777
|
-
|
|
1778
|
-
# 安装依赖
|
|
1779
|
-
npm install
|
|
1780
|
-
|
|
1781
|
-
# 运行测试
|
|
1782
|
-
npm test
|
|
1783
|
-
|
|
1784
|
-
# 运行基准测试
|
|
1785
|
-
npm run benchmark
|
|
1786
|
-
```
|
|
1787
|
-
|
|
1788
|
-
---
|
|
1789
|
-
|
|
1790
|
-
## 📄 许可证
|
|
1791
|
-
|
|
1792
|
-
[MIT License](./LICENSE)
|
|
1793
|
-
|
|
1794
|
-
---
|
|
1795
|
-
|
|
1796
|
-
## 💬 社区与支持
|
|
1797
|
-
|
|
1798
|
-
- 📧 **Email**: support@monsqlize.dev
|
|
1799
|
-
- 💬 **Issues**: [GitHub Issues](https://github.com/vextjs/monSQLize/issues)
|
|
1800
|
-
- 📖 **文档**: [完整文档](./docs/INDEX.md)
|
|
1801
|
-
- 🌟 **Star**: 如果觉得有用,请给我们一个 Star ⭐
|
|
1802
|
-
|
|
1803
|
-
---
|
|
1804
|
-
|
|
1805
|
-
## 🎉 快速链接
|
|
1806
|
-
|
|
1807
|
-
<div align="center">
|
|
1808
|
-
|
|
1809
|
-
**[🚀 快速开始](#-5分钟快速开始)** ·
|
|
1810
|
-
**[📚 完整文档](./docs/INDEX.md)** ·
|
|
1811
|
-
**[💻 示例代码](./examples/)** ·
|
|
1812
|
-
**[🐛 报告问题](https://github.com/vextjs/monSQLize/issues)** ·
|
|
1813
|
-
**[⭐ Star 项目](https://github.com/vextjs/monSQLize)**
|
|
1814
|
-
|
|
1815
|
-
---
|
|
1816
|
-
|
|
1817
|
-
### 让 MongoDB 快 10~100 倍,从现在开始 🚀
|
|
1818
|
-
|
|
1819
|
-
```bash
|
|
1820
|
-
npm install monsqlize
|
|
1821
|
-
```
|
|
1822
|
-
|
|
1823
|
-
---
|
|
1824
|
-
|
|
1825
|
-
Made with ❤️ by monSQLize Team
|
|
1826
|
-
|
|
1827
|
-
</div>
|
|
1828
|
-
|
|
1
|
+
# monSQLize
|
|
2
|
+
|
|
3
|
+
TypeScript-native MongoDB ODM and enhancement layer with v1-compatible APIs, multi-level caching, distributed locks, transactions, Saga orchestration, model validation, connection pools, Change Stream sync, slow-query logging, and CommonJS / ESM / TypeScript declaration outputs.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/monsqlize)
|
|
6
|
+
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
7
|
+
[](https://www.mongodb.com/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install monsqlize
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
monSQLize is currently a MongoDB-focused package. The long-term product direction is to keep the MongoDB-style query experience while gradually extending the same high-level API shape to additional database backends.
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Why monSQLize](#why-monsqlize)
|
|
19
|
+
- [When to Use It](#when-to-use-it)
|
|
20
|
+
- [Installation](#installation)
|
|
21
|
+
- [Quick Start](#quick-start)
|
|
22
|
+
- [Model Layer](#model-layer)
|
|
23
|
+
- [Caching and Performance](#caching-and-performance)
|
|
24
|
+
- [Advanced Capabilities](#advanced-capabilities)
|
|
25
|
+
- [Migration from the MongoDB Driver](#migration-from-the-mongodb-driver)
|
|
26
|
+
- [Compatibility](#compatibility)
|
|
27
|
+
- [Documentation](#documentation)
|
|
28
|
+
- [Development](#development)
|
|
29
|
+
- [Release Status](#release-status)
|
|
30
|
+
- [Roadmap](#roadmap)
|
|
31
|
+
- [License](#license)
|
|
32
|
+
- [Support](#support)
|
|
33
|
+
|
|
34
|
+
## Why monSQLize
|
|
35
|
+
|
|
36
|
+
monSQLize keeps the MongoDB driver mental model while adding the production features most teams end up building around it:
|
|
37
|
+
|
|
38
|
+
- Drop-in collection helpers that preserve MongoDB-style CRUD, aggregation, indexes, transactions, and Change Streams.
|
|
39
|
+
- Smart caching through `cache-hub`, including local memory caching, optional Redis-backed L2 caching, automatic invalidation, and function-level caching.
|
|
40
|
+
- A lightweight Model layer with `schema-dsl` validation, hooks, relations, populate, custom methods, timestamps, soft delete, and optimistic locking.
|
|
41
|
+
- Multi-connection-pool support, pool health checks, pool-scoped collections/models, and fallback strategies.
|
|
42
|
+
- Business locks and distributed locks for multi-instance deployments.
|
|
43
|
+
- Saga orchestration for multi-step business workflows.
|
|
44
|
+
- Change Stream sync helpers with resume token storage.
|
|
45
|
+
- Slow-query logging and query diagnostics.
|
|
46
|
+
- CommonJS, ESM, and TypeScript declaration outputs from `dist/**`.
|
|
47
|
+
|
|
48
|
+
## When to Use It
|
|
49
|
+
|
|
50
|
+
monSQLize is a good fit when you need:
|
|
51
|
+
|
|
52
|
+
| Scenario | Benefit |
|
|
53
|
+
|---|---|
|
|
54
|
+
| High-concurrency reads | Cache hot data and reduce repeated database work. |
|
|
55
|
+
| MongoDB API compatibility | Keep familiar query syntax while adding higher-level helpers. |
|
|
56
|
+
| Multi-instance services | Use Redis invalidation and distributed locks to keep instances coordinated. |
|
|
57
|
+
| Transaction-heavy flows | Use `withTransaction()` and transaction-aware helpers instead of hand-rolled lifecycle code. |
|
|
58
|
+
| Model-level ergonomics | Add schema validation, hooks, populate, and custom methods only where needed. |
|
|
59
|
+
| Smooth upgrade from v1 | Keep legacy application source stable while adopting the TypeScript rewrite. |
|
|
60
|
+
|
|
61
|
+
monSQLize is usually not the best first choice for pure write-heavy workloads, extremely strict real-time reads where every query must bypass cache, or very small applications that do not need the extra operational layer.
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install monsqlize
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Runtime dependencies installed with the package:
|
|
70
|
+
|
|
71
|
+
- `mongodb` - official MongoDB driver.
|
|
72
|
+
- `schema-dsl` - model schema validation runtime dependency.
|
|
73
|
+
- `cache-hub` - cache and function-cache foundation.
|
|
74
|
+
- `async-lock` - local concurrency lock support.
|
|
75
|
+
|
|
76
|
+
Optional dependencies:
|
|
77
|
+
|
|
78
|
+
- `ioredis` - required only when you enable Redis / L2 cache features.
|
|
79
|
+
- `ssh2` - required only when you connect through an SSH tunnel.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm install ioredis ssh2
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
|
|
87
|
+
### CommonJS
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
const MonSQLize = require('monsqlize');
|
|
91
|
+
|
|
92
|
+
const db = new MonSQLize({
|
|
93
|
+
type: 'mongodb',
|
|
94
|
+
databaseName: 'mydb',
|
|
95
|
+
config: {
|
|
96
|
+
uri: 'mongodb://localhost:27017'
|
|
97
|
+
},
|
|
98
|
+
cache: {
|
|
99
|
+
enabled: true,
|
|
100
|
+
ttl: 60_000
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await db.connect();
|
|
105
|
+
|
|
106
|
+
const users = db.collection('users');
|
|
107
|
+
|
|
108
|
+
await users.insertOne({
|
|
109
|
+
username: 'john',
|
|
110
|
+
email: 'john@example.com',
|
|
111
|
+
createdAt: new Date()
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const user = await users.findOne({ email: 'john@example.com' });
|
|
115
|
+
const userById = await users.findOneById('507f1f77bcf86cd799439011');
|
|
116
|
+
|
|
117
|
+
await users.updateOne(
|
|
118
|
+
{ email: 'john@example.com' },
|
|
119
|
+
{ $set: { lastLoginAt: new Date() } }
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
await db.close();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### ESM and TypeScript
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import MonSQLize from 'monsqlize';
|
|
129
|
+
import type { Collection } from 'monsqlize';
|
|
130
|
+
|
|
131
|
+
const db = new MonSQLize({
|
|
132
|
+
type: 'mongodb',
|
|
133
|
+
databaseName: 'mydb',
|
|
134
|
+
config: {
|
|
135
|
+
uri: 'mongodb://localhost:27017'
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await db.connect();
|
|
140
|
+
|
|
141
|
+
const users: Collection = db.collection('users');
|
|
142
|
+
const activeUsers = await users.find({ status: 'active' }).toArray();
|
|
143
|
+
|
|
144
|
+
await db.close();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Published entry points:
|
|
148
|
+
|
|
149
|
+
| Format | Entry |
|
|
150
|
+
|---|---|
|
|
151
|
+
| CommonJS | `dist/cjs/index.cjs` |
|
|
152
|
+
| ESM | `dist/esm/index.mjs` |
|
|
153
|
+
| Types | `dist/types/index.d.ts` |
|
|
154
|
+
|
|
155
|
+
The package root exports only the public package contract. Deep imports into historical `lib/**` files are not part of the v2 publishing surface.
|
|
156
|
+
|
|
157
|
+
## Model Layer
|
|
158
|
+
|
|
159
|
+
The Model layer is optional. Use it when you want schema validation, hooks, relations, populate, custom methods, timestamps, soft delete, or optimistic locking.
|
|
160
|
+
|
|
161
|
+
`schema-dsl` is installed automatically as a runtime dependency of monSQLize. You only need to declare `schema-dsl` in your own app if your application imports it directly.
|
|
162
|
+
|
|
163
|
+
### Manual Model Registration
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
const MonSQLize = require('monsqlize');
|
|
167
|
+
const { Model } = MonSQLize;
|
|
168
|
+
|
|
169
|
+
Model.define('users', {
|
|
170
|
+
schema: (dsl) => dsl({
|
|
171
|
+
username: 'string:3-32!',
|
|
172
|
+
email: 'email!',
|
|
173
|
+
password: 'string:6-!',
|
|
174
|
+
age: 'number:0-120'
|
|
175
|
+
}),
|
|
176
|
+
relations: {
|
|
177
|
+
posts: {
|
|
178
|
+
from: 'posts',
|
|
179
|
+
localField: '_id',
|
|
180
|
+
foreignField: 'userId',
|
|
181
|
+
single: false
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
hooks: (model) => ({
|
|
185
|
+
insert: {
|
|
186
|
+
before: async (ctx, doc) => {
|
|
187
|
+
doc.createdAt = new Date();
|
|
188
|
+
return doc;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}),
|
|
192
|
+
methods: (model) => ({
|
|
193
|
+
instance: {
|
|
194
|
+
checkPassword(password) {
|
|
195
|
+
return this.password === password;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
static: {
|
|
199
|
+
async findByUsername(username) {
|
|
200
|
+
return model.findOne({ username });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const db = new MonSQLize({
|
|
207
|
+
type: 'mongodb',
|
|
208
|
+
databaseName: 'mydb',
|
|
209
|
+
config: { uri: 'mongodb://localhost:27017' }
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await db.connect();
|
|
213
|
+
|
|
214
|
+
const User = db.model('users');
|
|
215
|
+
const user = await User.insertOne({
|
|
216
|
+
username: 'john',
|
|
217
|
+
email: 'john@example.com',
|
|
218
|
+
password: 'secret123',
|
|
219
|
+
age: 25
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Automatic Model Loading
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
const path = require('path');
|
|
227
|
+
const MonSQLize = require('monsqlize');
|
|
228
|
+
|
|
229
|
+
const db = new MonSQLize({
|
|
230
|
+
type: 'mongodb',
|
|
231
|
+
databaseName: 'mydb',
|
|
232
|
+
config: { uri: 'mongodb://localhost:27017' },
|
|
233
|
+
models: path.join(__dirname, 'models')
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await db.connect();
|
|
237
|
+
|
|
238
|
+
const User = db.model('users');
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
// models/user.model.js
|
|
243
|
+
module.exports = {
|
|
244
|
+
name: 'users',
|
|
245
|
+
schema: (dsl) => dsl({
|
|
246
|
+
username: 'string:3-32!',
|
|
247
|
+
email: 'email!'
|
|
248
|
+
}),
|
|
249
|
+
methods: (model) => ({
|
|
250
|
+
static: {
|
|
251
|
+
async findByUsername(username) {
|
|
252
|
+
return model.findOne({ username });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
};
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Relative model paths are resolved from `process.cwd()`. In production services, prefer absolute paths such as `path.join(__dirname, 'models')`.
|
|
260
|
+
|
|
261
|
+
### Populate
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
Model.define('posts', {
|
|
265
|
+
schema: (dsl) => dsl({
|
|
266
|
+
title: 'string:1-200!',
|
|
267
|
+
content: 'string!',
|
|
268
|
+
userId: 'objectId!'
|
|
269
|
+
})
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const userWithPosts = await User.findOne({ username: 'john' })
|
|
273
|
+
.populate('posts', {
|
|
274
|
+
select: 'title content',
|
|
275
|
+
match: { status: 'published' },
|
|
276
|
+
sort: { createdAt: -1 },
|
|
277
|
+
limit: 10
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Populate is supported by `find()`, `findOne()`, `findByIds()`, `findOneById()`, `findAndCount()`, and `findPage()`.
|
|
282
|
+
|
|
283
|
+
## Caching and Performance
|
|
284
|
+
|
|
285
|
+
monSQLize can cache collection queries and arbitrary async functions.
|
|
286
|
+
|
|
287
|
+
```js
|
|
288
|
+
const users = db.collection('users');
|
|
289
|
+
|
|
290
|
+
const hotUser = await users.findOne(
|
|
291
|
+
{ email: 'john@example.com' },
|
|
292
|
+
{ cache: 60_000 }
|
|
293
|
+
);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
const { withCache } = require('monsqlize');
|
|
298
|
+
|
|
299
|
+
async function getUserProfile(userId) {
|
|
300
|
+
const user = await db.collection('users').findOneById(userId);
|
|
301
|
+
const orders = await db.collection('orders').find({ userId }).toArray();
|
|
302
|
+
return { user, orders };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const cachedGetUserProfile = withCache(getUserProfile, {
|
|
306
|
+
ttl: 300_000,
|
|
307
|
+
cache: db.getCache()
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
await cachedGetUserProfile('user-1');
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Cache capabilities include:
|
|
314
|
+
|
|
315
|
+
- In-memory L1 cache.
|
|
316
|
+
- Optional Redis-backed L2 cache.
|
|
317
|
+
- Automatic invalidation after writes.
|
|
318
|
+
- Function-level caching through `withCache()`.
|
|
319
|
+
- In-flight request deduplication.
|
|
320
|
+
- Namespaces, TTLs, statistics, and conditional caching.
|
|
321
|
+
|
|
322
|
+
## Advanced Capabilities
|
|
323
|
+
|
|
324
|
+
### Transactions
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
await db.withTransaction(async (session) => {
|
|
328
|
+
await db.collection('orders').insertOne({ userId, status: 'pending' }, { session });
|
|
329
|
+
await db.collection('users').updateOne(
|
|
330
|
+
{ _id: userId },
|
|
331
|
+
{ $inc: { orderCount: 1 } },
|
|
332
|
+
{ session }
|
|
333
|
+
);
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Connection Pools
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
const db = new MonSQLize({
|
|
341
|
+
type: 'mongodb',
|
|
342
|
+
databaseName: 'main',
|
|
343
|
+
config: { uri: 'mongodb://primary:27017' },
|
|
344
|
+
pools: [
|
|
345
|
+
{ name: 'analytics', uri: 'mongodb://analytics:27017' }
|
|
346
|
+
]
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const reports = db.pool('analytics').collection('reports');
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Distributed Locks
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
await db.withLock('inventory:sku-1', async () => {
|
|
356
|
+
await db.collection('inventory').updateOne(
|
|
357
|
+
{ sku: 'sku-1' },
|
|
358
|
+
{ $inc: { stock: -1 } }
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Change Streams
|
|
364
|
+
|
|
365
|
+
```js
|
|
366
|
+
const watcher = db.collection('orders').watch([
|
|
367
|
+
{ $match: { 'fullDocument.status': 'pending' } }
|
|
368
|
+
]);
|
|
369
|
+
|
|
370
|
+
watcher.on('change', (change) => {
|
|
371
|
+
console.log('Order changed:', change.fullDocument);
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Saga Orchestration
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
db.defineSaga('checkout', [
|
|
379
|
+
{
|
|
380
|
+
name: 'reserveInventory',
|
|
381
|
+
execute: async (ctx) => reserveInventory(ctx),
|
|
382
|
+
compensate: async (ctx) => releaseInventory(ctx)
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: 'chargePayment',
|
|
386
|
+
execute: async (ctx) => chargePayment(ctx),
|
|
387
|
+
compensate: async (ctx) => refundPayment(ctx)
|
|
388
|
+
}
|
|
389
|
+
]);
|
|
390
|
+
|
|
391
|
+
await db.executeSaga('checkout', { orderId });
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Migration from the MongoDB Driver
|
|
395
|
+
|
|
396
|
+
The smallest migration is usually to replace only initialization:
|
|
397
|
+
|
|
398
|
+
```js
|
|
399
|
+
const { MongoClient } = require('mongodb');
|
|
400
|
+
|
|
401
|
+
const nativeClient = await MongoClient.connect('mongodb://localhost:27017');
|
|
402
|
+
const nativeUsers = nativeClient.db('mydb').collection('users');
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
```js
|
|
406
|
+
const MonSQLize = require('monsqlize');
|
|
407
|
+
|
|
408
|
+
const db = new MonSQLize({
|
|
409
|
+
type: 'mongodb',
|
|
410
|
+
databaseName: 'mydb',
|
|
411
|
+
config: { uri: 'mongodb://localhost:27017' },
|
|
412
|
+
cache: { enabled: true }
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
await db.connect();
|
|
416
|
+
const users = db.collection('users');
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
MongoDB-style collection calls can remain unchanged in most cases:
|
|
420
|
+
|
|
421
|
+
```js
|
|
422
|
+
const user = await users.findOne({ email });
|
|
423
|
+
const list = await users.find({ status: 'active' }).toArray();
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
The current v2.0.0 release candidate has been validated against the workspace consumers `chat`, `payment`, `user`, `admin`, `search`, `vext`, and `permission-core` without requiring business-source changes in those projects.
|
|
427
|
+
|
|
428
|
+
## Compatibility
|
|
429
|
+
|
|
430
|
+
| Surface | Current Support |
|
|
431
|
+
|---|---|
|
|
432
|
+
| Node.js | `>=18.0.0`; CI covers Node 18 / 20 / 22. |
|
|
433
|
+
| MongoDB driver | `mongodb@^6.21.0` baseline; driver 7 has additional compatibility coverage. |
|
|
434
|
+
| MongoDB server | Memory-server based 6.x / 7.x validation is covered by the project test matrix. |
|
|
435
|
+
| Module systems | CommonJS and ESM are both validated. |
|
|
436
|
+
| TypeScript | Public declarations are published from `dist/types/index.d.ts`. |
|
|
437
|
+
| Package license | Apache-2.0. |
|
|
438
|
+
|
|
439
|
+
See the current support and verification documents:
|
|
440
|
+
|
|
441
|
+
- [docs/README.md](https://github.com/vextjs/monSQLize/blob/main/docs/README.md)
|
|
442
|
+
- [docs/support-matrix.md](https://github.com/vextjs/monSQLize/blob/main/docs/support-matrix.md)
|
|
443
|
+
- [docs/verification-entrypoints.md](https://github.com/vextjs/monSQLize/blob/main/docs/verification-entrypoints.md)
|
|
444
|
+
- [test/compatibility/README.md](https://github.com/vextjs/monSQLize/blob/main/test/compatibility/README.md)
|
|
445
|
+
- [test/validation/VERIFICATION-PROGRESS.md](https://github.com/vextjs/monSQLize/blob/main/test/validation/VERIFICATION-PROGRESS.md)
|
|
446
|
+
|
|
447
|
+
## Documentation
|
|
448
|
+
|
|
449
|
+
Current TypeScript documentation and examples are the source of truth for the v2 package:
|
|
450
|
+
|
|
451
|
+
- `docs/**` - current documentation.
|
|
452
|
+
- `examples/**` - TypeScript examples.
|
|
453
|
+
- `test/compatibility/**` - package exports and compatibility guards.
|
|
454
|
+
- `test/validation/**` - verification ledgers and mapping notes.
|
|
455
|
+
|
|
456
|
+
Historical v1 assets are useful for tracing old behavior, but they are not the current publishing surface for v2.
|
|
457
|
+
|
|
458
|
+
## Development
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
git clone https://github.com/vextjs/monSQLize.git
|
|
462
|
+
cd monSQLize
|
|
463
|
+
npm install
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Common commands:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
npm run build
|
|
470
|
+
npm run type-check
|
|
471
|
+
npm test
|
|
472
|
+
npm run verify:fast
|
|
473
|
+
npm run release:preflight
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Release preflight runs linting, type checks, size guards, runtime checks, compatibility checks, refactor guards, the default test suite, and `npm pack --dry-run`.
|
|
477
|
+
|
|
478
|
+
`npm run release:publish` runs the preflight gate once and then calls `npm publish --ignore-scripts` so the final publish step does not repeat the full lifecycle gate. Raw `npm publish` is still guarded by `prepublishOnly`.
|
|
479
|
+
|
|
480
|
+
Optional commands:
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
npm run test:examples
|
|
484
|
+
npm run test:coverage
|
|
485
|
+
npm run test:server-matrix
|
|
486
|
+
npm run test:real-env:private
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
`test:real-env:private` is intentionally opt-in and expects private environment variables. It is not part of the default CI or release gate.
|
|
490
|
+
|
|
491
|
+
## Release Status
|
|
492
|
+
|
|
493
|
+
The current release candidate is `v2.0.0`.
|
|
494
|
+
|
|
495
|
+
Key release-readiness points:
|
|
496
|
+
|
|
497
|
+
- TypeScript rewrite completed for the current runtime and test entry points.
|
|
498
|
+
- Package exports are consolidated under `dist/cjs`, `dist/esm`, and `dist/types`.
|
|
499
|
+
- npm packages include the runtime bundles and declaration files only; source maps are disabled by default and can be generated locally with `MONSQLIZE_BUILD_SOURCEMAPS=1 npm run build`.
|
|
500
|
+
- v1 smooth-upgrade compatibility has been validated against the target workspace consumers.
|
|
501
|
+
- `schema-dsl` follows the npm `latest` TypeScript line `^2.0.3`; deprecated `2.3.x` mistake releases are intentionally excluded.
|
|
502
|
+
- GitHub Actions publishes to npm from `v*` tags after running `npm run release:preflight`; the publish step skips duplicate lifecycle scripts because the gate already ran in the same job.
|
|
503
|
+
|
|
504
|
+
## Roadmap
|
|
505
|
+
|
|
506
|
+
### v2.0.0
|
|
507
|
+
|
|
508
|
+
- TypeScript-native runtime and declarations.
|
|
509
|
+
- v1 smooth-upgrade compatibility bridge.
|
|
510
|
+
- Multi-level cache and function-cache support through `cache-hub`.
|
|
511
|
+
- Transactions, business locks, distributed locks, Saga orchestration, connection pools, Change Stream sync, and slow-query logging.
|
|
512
|
+
- Model layer with `schema-dsl` validation, relations, populate, hooks, and custom methods.
|
|
513
|
+
|
|
514
|
+
### v2.x
|
|
515
|
+
|
|
516
|
+
- Query analyzer improvements.
|
|
517
|
+
- Automatic index suggestions.
|
|
518
|
+
- Migration tooling.
|
|
519
|
+
- GraphQL integration experiments.
|
|
520
|
+
- More real-environment validation coverage.
|
|
521
|
+
|
|
522
|
+
### v3.0+
|
|
523
|
+
|
|
524
|
+
- Unified API experiments for MySQL.
|
|
525
|
+
- Unified API experiments for PostgreSQL.
|
|
526
|
+
- Broader ORM capabilities.
|
|
527
|
+
- Cross-database sync middleware.
|
|
528
|
+
|
|
529
|
+
## License
|
|
530
|
+
|
|
531
|
+
monSQLize is released under the [Apache License 2.0](./LICENSE).
|
|
532
|
+
|
|
533
|
+
## Support
|
|
534
|
+
|
|
535
|
+
- Issues: [GitHub Issues](https://github.com/vextjs/monSQLize/issues)
|
|
536
|
+
- npm: [monsqlize](https://www.npmjs.com/package/monsqlize)
|
|
537
|
+
- Website: [https://vextjs.github.io/monSQLize/](https://vextjs.github.io/monSQLize/)
|