mm_mongodb 1.4.6 → 1.4.8

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/index.js CHANGED
@@ -21,15 +21,13 @@ class MongoDB extends eventEmitter {
21
21
  /**
22
22
  * @description 创建MongoDB帮助类函数 (构造函数)
23
23
  * @param {String} scope 作用域
24
- * @param {String} dir 当前路径
24
+ * @param {Object} config 配置参数
25
25
  * @constructor
26
26
  */
27
- constructor(scope, dir, config) {
27
+ constructor(scope, config) {
28
28
  super();
29
29
  // 作用域
30
30
  this.scope = scope || ($.val && $.val.scope ? String($.val.scope) : 'default');
31
- // 当前目录
32
- this.dir = dir || __dirname;
33
31
 
34
32
  // 从环境变量加载配置
35
33
  const envConfig = this._loadEnvConfig();
@@ -64,8 +62,9 @@ class MongoDB extends eventEmitter {
64
62
  maxAttempts: 3,
65
63
  delayMS: 1000
66
64
  }
67
- }, envConfig, config);
65
+ }, envConfig);
68
66
 
67
+ this.setConfig(config);
69
68
  // 验证配置
70
69
  this._validateConfig();
71
70
 
@@ -87,6 +86,11 @@ class MongoDB extends eventEmitter {
87
86
  this.size = 0;
88
87
  // 连接状态
89
88
  this.connected = false;
89
+ // 连接Promise缓存
90
+ this.connectPromise = null;
91
+ // 连接重试次数
92
+ this.connectAttempts = 0;
93
+ this.maxConnectAttempts = 3;
90
94
  }
91
95
 
92
96
  /**
@@ -154,7 +158,89 @@ class MongoDB extends eventEmitter {
154
158
  // 所有重试都失败,抛出最后一个错误
155
159
  throw lastError;
156
160
  }
157
-
161
+
162
+ /**
163
+ * @description 确保数据库连接已建立
164
+ * @private
165
+ * @return {Promise<void>}
166
+ */
167
+ async _ensureConnected() {
168
+ // 如果已有连接Promise,等待其完成
169
+ if (this.connectPromise) {
170
+ return this.connectPromise;
171
+ }
172
+
173
+ // 创建新的连接Promise
174
+ this.connectPromise = (async () => {
175
+ try {
176
+ // 检查连接状态
177
+ if (!this.db || !this.connected) {
178
+ // 记录连接尝试
179
+ this.connectAttempts++;
180
+
181
+ // 尝试连接
182
+ await this.open();
183
+
184
+ // 检查连接是否成功
185
+ if (this.db && this.db.collection) {
186
+ this.connected = true;
187
+ this.connectAttempts = 0;
188
+
189
+ // 确保索引已创建
190
+ await this._ensureIndexes();
191
+
192
+ $.log.info(`[MongoDB] 成功连接到数据库,表名: ${this.table}`);
193
+ } else {
194
+ throw new Error('数据库连接失败,db对象为空');
195
+ }
196
+ }
197
+ } catch (error) {
198
+ $.log.error(`[MongoDB] 连接失败 (尝试 ${this.connectAttempts}/${this.maxConnectAttempts}):`, error.message);
199
+
200
+ // 重置连接Promise,允许下次重试
201
+ this.connectPromise = null;
202
+
203
+ // 如果尝试次数未超过限制,抛出错误让上层处理
204
+ if (this.connectAttempts < this.maxConnectAttempts) {
205
+ throw error;
206
+ } else {
207
+ // 超过重试次数,记录严重错误
208
+ $.log.error('[MongoDB] 达到最大连接重试次数,连接失败');
209
+ throw new Error('数据库连接失败,已达到最大重试次数');
210
+ }
211
+ }
212
+ })();
213
+
214
+ return this.connectPromise;
215
+ }
216
+
217
+ /**
218
+ * @description 确保索引已创建
219
+ * @private
220
+ * @return {Promise<void>}
221
+ */
222
+ async _ensureIndexes() {
223
+ try {
224
+ // 确保db对象有效
225
+ if (!this.db || !this.db.collection) {
226
+ throw new Error('数据库连接无效,无法创建索引');
227
+ }
228
+
229
+ // 创建TTL索引用于自动过期
230
+ await this.db.collection(this.table).createIndex(
231
+ { expireAt: 1 },
232
+ { expireAfterSeconds: 0 }
233
+ );
234
+ // 创建_id索引(通常自动创建,但显式指定更清晰)
235
+ await this.db.collection(this.table).createIndex({ _id: 1 });
236
+ } catch (error) {
237
+ // 忽略索引已存在的错误
238
+ if (error.code !== 85) {
239
+ $.log.error('[MongoDB] 创建索引失败:', error);
240
+ }
241
+ }
242
+ }
243
+
158
244
  /**
159
245
  * @description Redis兼容API - 获取缓存值
160
246
  * @param {String} key 键名
@@ -162,6 +248,7 @@ class MongoDB extends eventEmitter {
162
248
  */
163
249
  async get(key) {
164
250
  try {
251
+ await this._ensureConnected();
165
252
  const result = await this.findOne({ key: key });
166
253
  return result ? result.value : null;
167
254
  } catch (error) {
@@ -169,13 +256,14 @@ class MongoDB extends eventEmitter {
169
256
  return null;
170
257
  }
171
258
  }
172
-
259
+
173
260
  /**
174
261
  * @description Redis兼容API - 清空所有缓存
175
262
  * @return {Promise<Boolean>} 是否成功
176
263
  */
177
264
  async clear() {
178
265
  try {
266
+ await this._ensureConnected();
179
267
  await this.del({});
180
268
  return true;
181
269
  } catch (error) {
@@ -183,7 +271,7 @@ class MongoDB extends eventEmitter {
183
271
  return false;
184
272
  }
185
273
  }
186
-
274
+
187
275
  /**
188
276
  * @description Redis兼容API - 获取所有键
189
277
  * @param {String} pattern 匹配模式
@@ -191,6 +279,7 @@ class MongoDB extends eventEmitter {
191
279
  */
192
280
  async keys(pattern = '*') {
193
281
  try {
282
+ await this._ensureConnected();
194
283
  let query = {};
195
284
  if (pattern !== '*') {
196
285
  // 简单的通配符支持
@@ -204,7 +293,7 @@ class MongoDB extends eventEmitter {
204
293
  return [];
205
294
  }
206
295
  }
207
-
296
+
208
297
  /**
209
298
  * @description Redis兼容API - 设置过期时间
210
299
  * @param {String} key 键名
@@ -213,6 +302,7 @@ class MongoDB extends eventEmitter {
213
302
  */
214
303
  async ttl(key, seconds) {
215
304
  try {
305
+ await this._ensureConnected();
216
306
  if (!seconds && seconds !== 0) {
217
307
  // 获取剩余过期时间
218
308
  const item = await this.findOne({ key: key });
@@ -222,7 +312,7 @@ class MongoDB extends eventEmitter {
222
312
  } else {
223
313
  // 设置过期时间
224
314
  const expireAt = seconds === 0 ? null : new Date(Date.now() + seconds * 1000);
225
- const result = await this.set({ key: key }, { expireAt: expireAt });
315
+ const result = await this._set({ key: key }, { expireAt: expireAt });
226
316
  return result.modifiedCount > 0;
227
317
  }
228
318
  } catch (error) {
@@ -230,7 +320,7 @@ class MongoDB extends eventEmitter {
230
320
  return false;
231
321
  }
232
322
  }
233
-
323
+
234
324
  /**
235
325
  * @description Redis兼容API - 添加缓存
236
326
  * @param {String} key 键名
@@ -238,21 +328,22 @@ class MongoDB extends eventEmitter {
238
328
  * @param {Number} expire 过期时间(秒)
239
329
  * @return {Promise<Boolean>} 是否成功
240
330
  */
241
- async add(key, value, expire) {
331
+ async _add(key, value, expire) {
242
332
  try {
333
+ await this._ensureConnected();
243
334
  const data = {
244
335
  key: key,
245
336
  value: value
246
337
  };
247
-
338
+
248
339
  if (expire) {
249
340
  data.expireAt = new Date(Date.now() + expire * 1000);
250
341
  }
251
-
342
+
252
343
  // 检查是否已存在
253
344
  const existing = await this.findOne({ key: key });
254
345
  if (existing) {
255
- await this.set({ key: key }, data);
346
+ await this._set({ key: key }, data);
256
347
  } else {
257
348
  await this.addObj(data);
258
349
  }
@@ -262,7 +353,18 @@ class MongoDB extends eventEmitter {
262
353
  return false;
263
354
  }
264
355
  }
265
-
356
+
357
+ /**
358
+ * @description Redis兼容API - 添加缓存
359
+ * @param {String} key 键名
360
+ * @param {*} value 值
361
+ * @param {Number} expire 过期时间(秒)
362
+ * @return {Promise<Boolean>} 是否成功
363
+ */
364
+ async add(key, value, expire) {
365
+ return this._add(key, value, expire);
366
+ }
367
+
266
368
  /**
267
369
  * @description Redis兼容API - 增加整数值
268
370
  * @param {String} key 键名
@@ -271,22 +373,23 @@ class MongoDB extends eventEmitter {
271
373
  */
272
374
  async addInt(key, value = 1) {
273
375
  try {
376
+ await this._ensureConnected();
274
377
  const item = await this.findOne({ key: key });
275
378
  let currentValue = 0;
276
-
379
+
277
380
  if (item && typeof item.value === 'number') {
278
381
  currentValue = item.value;
279
382
  }
280
-
383
+
281
384
  const newValue = currentValue + value;
282
- await this.add(key, newValue);
385
+ await this._add(key, newValue);
283
386
  return newValue;
284
387
  } catch (error) {
285
388
  $.log.error('[MongoDB] 增加整数值失败:', error);
286
389
  return undefined;
287
390
  }
288
391
  }
289
-
392
+
290
393
  /**
291
394
  * @description Redis兼容API - 增加浮点数值
292
395
  * @param {String} key 键名
@@ -296,7 +399,7 @@ class MongoDB extends eventEmitter {
296
399
  async addFloat(key, value = 1.0) {
297
400
  return this.addInt(key, value); // 复用addInt方法
298
401
  }
299
-
402
+
300
403
  /**
301
404
  * @description Redis兼容API - 添加字符串
302
405
  * @param {String} key 键名
@@ -304,9 +407,9 @@ class MongoDB extends eventEmitter {
304
407
  * @return {Promise<Boolean>} 是否成功
305
408
  */
306
409
  async addStr(key, value) {
307
- return this.add(key, String(value));
410
+ return this._add(key, String(value));
308
411
  }
309
-
412
+
310
413
  /**
311
414
  * @description Redis兼容API - 排序
312
415
  * @param {String} key 键名
@@ -315,32 +418,33 @@ class MongoDB extends eventEmitter {
315
418
  */
316
419
  async sort(key, options = {}) {
317
420
  try {
421
+ await this._ensureConnected();
318
422
  // 假设value是数组
319
423
  const item = await this.findOne({ key: key });
320
424
  if (!item || !Array.isArray(item.value)) return [];
321
-
425
+
322
426
  const sorted = [...item.value];
323
-
427
+
324
428
  // 处理排序选项
325
429
  if (options.desc) {
326
430
  sorted.sort((a, b) => b - a);
327
431
  } else {
328
432
  sorted.sort((a, b) => a - b);
329
433
  }
330
-
434
+
331
435
  // 处理限制
332
436
  if (options.limit) {
333
437
  const offset = options.offset || 0;
334
438
  return sorted.slice(offset, offset + options.limit);
335
439
  }
336
-
440
+
337
441
  return sorted;
338
442
  } catch (error) {
339
443
  $.log.error('[MongoDB] 排序失败:', error);
340
444
  return [];
341
445
  }
342
446
  }
343
-
447
+
344
448
  /**
345
449
  * @description Redis兼容API - 哈希表设置字段
346
450
  * @param {String} key 键名
@@ -350,18 +454,19 @@ class MongoDB extends eventEmitter {
350
454
  */
351
455
  async hset(key, field, value) {
352
456
  try {
457
+ await this._ensureConnected();
353
458
  const item = await this.findOne({ key: key });
354
459
  let hash = item && typeof item.value === 'object' && item.value !== null ? item.value : {};
355
-
460
+
356
461
  hash[field] = value;
357
- await this.add(key, hash);
462
+ await this._add(key, hash);
358
463
  return true;
359
464
  } catch (error) {
360
465
  $.log.error('[MongoDB] 哈希表设置失败:', error);
361
466
  return false;
362
467
  }
363
468
  }
364
-
469
+
365
470
  /**
366
471
  * @description Redis兼容API - 哈希表获取字段
367
472
  * @param {String} key 键名
@@ -370,6 +475,7 @@ class MongoDB extends eventEmitter {
370
475
  */
371
476
  async hget(key, field) {
372
477
  try {
478
+ await this._ensureConnected();
373
479
  const item = await this.findOne({ key: key });
374
480
  if (!item || typeof item.value !== 'object' || item.value === null) {
375
481
  return null;
@@ -380,7 +486,7 @@ class MongoDB extends eventEmitter {
380
486
  return null;
381
487
  }
382
488
  }
383
-
489
+
384
490
  /**
385
491
  * @description Redis兼容API - 哈希表获取所有字段和值
386
492
  * @param {String} key 键名
@@ -398,7 +504,7 @@ class MongoDB extends eventEmitter {
398
504
  return {};
399
505
  }
400
506
  }
401
-
507
+
402
508
  /**
403
509
  * @description Redis兼容API - 哈希表删除字段
404
510
  * @param {String} key 键名
@@ -411,20 +517,20 @@ class MongoDB extends eventEmitter {
411
517
  if (!item || typeof item.value !== 'object' || item.value === null) {
412
518
  return false;
413
519
  }
414
-
520
+
415
521
  if (item.value[field] === undefined) {
416
522
  return false;
417
523
  }
418
-
524
+
419
525
  delete item.value[field];
420
- await this.set({ key: key }, { value: item.value });
526
+ await this._set({ key: key }, { value: item.value });
421
527
  return true;
422
528
  } catch (error) {
423
529
  $.log.error('[MongoDB] 哈希表删除失败:', error);
424
530
  return false;
425
531
  }
426
532
  }
427
-
533
+
428
534
  /**
429
535
  * @description Redis兼容API - 检查键是否存在
430
536
  * @param {String} key 键名
@@ -439,7 +545,7 @@ class MongoDB extends eventEmitter {
439
545
  return false;
440
546
  }
441
547
  }
442
-
548
+
443
549
  /**
444
550
  * @description Redis兼容API - 设置键过期时间(映射到ttl)
445
551
  * @param {String} key 键名
@@ -449,50 +555,81 @@ class MongoDB extends eventEmitter {
449
555
  async expire(key, seconds) {
450
556
  return this.ttl(key, seconds);
451
557
  }
452
-
558
+
453
559
  /**
454
560
  * @description Redis兼容API - 递增(通过addInt模拟)
455
561
  * @param {String} key 键名
456
562
  * @return {Promise<Number>} 递增后的值
457
563
  */
458
564
  async incr(key) {
459
- return this.addInt(key, 1);
565
+ try {
566
+ await this._ensureConnected();
567
+ const result = await this.addInt(key, 1);
568
+ return result !== undefined ? result : 0;
569
+ } catch (error) {
570
+ $.log.error('[MongoDB] 递增操作失败:', error);
571
+ return 0;
572
+ }
460
573
  }
461
-
574
+
462
575
  /**
463
576
  * @description Redis兼容API - 递减(通过addInt模拟)
464
577
  * @param {String} key 键名
465
578
  * @return {Promise<Number>} 递减后的值
466
579
  */
467
580
  async decr(key) {
468
- return this.addInt(key, -1);
581
+ try {
582
+ await this._ensureConnected();
583
+ const result = await this.addInt(key, -1);
584
+ return result !== undefined ? result : 0;
585
+ } catch (error) {
586
+ $.log.error('[MongoDB] 递减操作失败:', error);
587
+ return 0;
588
+ }
469
589
  }
470
-
590
+
471
591
  /**
472
592
  * @description Redis兼容API - 检查键是否存在(别名)
473
593
  * @param {String} key 键名
474
594
  * @return {Promise<Boolean>} 是否存在
475
595
  */
476
596
  async exists(key) {
477
- return this.has(key);
597
+ try {
598
+ await this._ensureConnected();
599
+ return this.has(key);
600
+ } catch (error) {
601
+ $.log.error('[MongoDB] 检查键是否存在失败:', error);
602
+ return false;
603
+ }
478
604
  }
479
-
605
+
480
606
  /**
481
607
  * @description Redis兼容API - 设置键值
482
608
  * @param {String} key 键名
483
609
  * @param {*} value 值
484
610
  * @return {Promise<Boolean>} 是否成功
485
611
  */
486
- async set(key, value) {
612
+ async _set(key, value) {
487
613
  try {
614
+ await this._ensureConnected();
488
615
  // 直接使用已有的add方法,它已正确处理查询条件格式
489
- return await this.add(key, value);
616
+ return await this._add(key, value);
490
617
  } catch (error) {
491
618
  $.log.error('[MongoDB] 设置键值失败:', error);
492
619
  return false;
493
620
  }
494
621
  }
495
-
622
+
623
+ /**
624
+ * @description Redis兼容API - 设置键值
625
+ * @param {String} key 键名
626
+ * @param {*} value 值
627
+ * @return {Promise<Boolean>} 是否成功
628
+ */
629
+ async set(key, value) {
630
+ return this._set(key, value);
631
+ }
632
+
496
633
  /**
497
634
  * @description Redis兼容API - 哈希表批量设置
498
635
  * @param {String} key 键名
@@ -501,19 +638,20 @@ class MongoDB extends eventEmitter {
501
638
  */
502
639
  async hmset(key, fieldValues) {
503
640
  try {
641
+ await this._ensureConnected();
504
642
  const item = await this.findOne({ key: key });
505
643
  let hash = item && typeof item.value === 'object' && item.value !== null ? item.value : {};
506
-
644
+
507
645
  // 合并字段值
508
646
  Object.assign(hash, fieldValues);
509
- await this.add(key, hash);
647
+ await this._add(key, hash);
510
648
  return true;
511
649
  } catch (error) {
512
650
  $.log.error('[MongoDB] 哈希表批量设置失败:', error);
513
651
  return false;
514
652
  }
515
653
  }
516
-
654
+
517
655
  /**
518
656
  * @description Redis兼容API - 哈希表批量获取
519
657
  * @param {String} key 键名
@@ -522,11 +660,12 @@ class MongoDB extends eventEmitter {
522
660
  */
523
661
  async hmget(key, fields) {
524
662
  try {
663
+ await this._ensureConnected();
525
664
  const item = await this.findOne({ key: key });
526
665
  if (!item || typeof item.value !== 'object' || item.value === null) {
527
666
  return {};
528
667
  }
529
-
668
+
530
669
  const result = {};
531
670
  fields.forEach(field => {
532
671
  result[field] = item.value[field] !== undefined ? item.value[field] : null;
@@ -537,7 +676,7 @@ class MongoDB extends eventEmitter {
537
676
  return {};
538
677
  }
539
678
  }
540
-
679
+
541
680
  /**
542
681
  * @description Redis兼容API - 哈希表批量删除字段
543
682
  * @param {String} key 键名
@@ -546,11 +685,12 @@ class MongoDB extends eventEmitter {
546
685
  */
547
686
  async hdelMulti(key, fields) {
548
687
  try {
688
+ await this._ensureConnected();
549
689
  const item = await this.findOne({ key: key });
550
690
  if (!item || typeof item.value !== 'object' || item.value === null) {
551
691
  return false;
552
692
  }
553
-
693
+
554
694
  let deleted = false;
555
695
  fields.forEach(field => {
556
696
  if (item.value[field] !== undefined) {
@@ -558,9 +698,9 @@ class MongoDB extends eventEmitter {
558
698
  deleted = true;
559
699
  }
560
700
  });
561
-
701
+
562
702
  if (deleted) {
563
- await this.set({ key: key }, { value: item.value });
703
+ await this._set({ key: key }, { value: item.value });
564
704
  }
565
705
  return deleted;
566
706
  } catch (error) {
@@ -568,7 +708,7 @@ class MongoDB extends eventEmitter {
568
708
  return false;
569
709
  }
570
710
  }
571
-
711
+
572
712
  /**
573
713
  * @description Redis兼容API - 哈希表获取所有值
574
714
  * @param {String} key 键名
@@ -576,6 +716,7 @@ class MongoDB extends eventEmitter {
576
716
  */
577
717
  async hvals(key) {
578
718
  try {
719
+ await this._ensureConnected();
579
720
  const item = await this.findOne({ key: key });
580
721
  if (!item || typeof item.value !== 'object' || item.value === null) {
581
722
  return [];
@@ -586,7 +727,7 @@ class MongoDB extends eventEmitter {
586
727
  return [];
587
728
  }
588
729
  }
589
-
730
+
590
731
  /**
591
732
  * @description Redis兼容API - 哈希表获取所有字段名
592
733
  * @param {String} key 键名
@@ -594,6 +735,7 @@ class MongoDB extends eventEmitter {
594
735
  */
595
736
  async hkeys(key) {
596
737
  try {
738
+ await this._ensureConnected();
597
739
  const item = await this.findOne({ key: key });
598
740
  if (!item || typeof item.value !== 'object' || item.value === null) {
599
741
  return [];
@@ -604,7 +746,7 @@ class MongoDB extends eventEmitter {
604
746
  return [];
605
747
  }
606
748
  }
607
-
749
+
608
750
  /**
609
751
  * @description Redis兼容API - 哈希表字段数量
610
752
  * @param {String} key 键名
@@ -612,6 +754,7 @@ class MongoDB extends eventEmitter {
612
754
  */
613
755
  async hlen(key) {
614
756
  try {
757
+ await this._ensureConnected();
615
758
  const item = await this.findOne({ key: key });
616
759
  if (!item || typeof item.value !== 'object' || item.value === null) {
617
760
  return 0;
@@ -622,7 +765,7 @@ class MongoDB extends eventEmitter {
622
765
  return 0;
623
766
  }
624
767
  }
625
-
768
+
626
769
  /**
627
770
  * @description Redis兼容API - 哈希表字段是否存在
628
771
  * @param {String} key 键名
@@ -631,6 +774,7 @@ class MongoDB extends eventEmitter {
631
774
  */
632
775
  async hexists(key, field) {
633
776
  try {
777
+ await this._ensureConnected();
634
778
  const item = await this.findOne({ key: key });
635
779
  if (!item || typeof item.value !== 'object' || item.value === null) {
636
780
  return false;
@@ -641,7 +785,7 @@ class MongoDB extends eventEmitter {
641
785
  return false;
642
786
  }
643
787
  }
644
-
788
+
645
789
  /**
646
790
  * @description Redis兼容API - 列表尾部添加元素
647
791
  * @param {String} key 键名
@@ -650,18 +794,19 @@ class MongoDB extends eventEmitter {
650
794
  */
651
795
  async rpush(key, value) {
652
796
  try {
797
+ await this._ensureConnected();
653
798
  const item = await this.findOne({ key: key });
654
799
  let list = item && Array.isArray(item.value) ? item.value : [];
655
-
800
+
656
801
  list.push(value);
657
- await this.add(key, list);
802
+ await this._add(key, list);
658
803
  return list.length;
659
804
  } catch (error) {
660
805
  $.log.error('[MongoDB] 列表尾部添加失败:', error);
661
806
  return 0;
662
807
  }
663
808
  }
664
-
809
+
665
810
  /**
666
811
  * @description Redis兼容API - 列表头部添加元素
667
812
  * @param {String} key 键名
@@ -670,18 +815,19 @@ class MongoDB extends eventEmitter {
670
815
  */
671
816
  async lpush(key, value) {
672
817
  try {
818
+ await this._ensureConnected();
673
819
  const item = await this.findOne({ key: key });
674
820
  let list = item && Array.isArray(item.value) ? item.value : [];
675
-
821
+
676
822
  list.unshift(value);
677
- await this.add(key, list);
823
+ await this._add(key, list);
678
824
  return list.length;
679
825
  } catch (error) {
680
826
  $.log.error('[MongoDB] 列表头部添加失败:', error);
681
827
  return 0;
682
828
  }
683
829
  }
684
-
830
+
685
831
  /**
686
832
  * @description Redis兼容API - 列表范围查询
687
833
  * @param {String} key 键名
@@ -691,26 +837,27 @@ class MongoDB extends eventEmitter {
691
837
  */
692
838
  async lrange(key, start, stop) {
693
839
  try {
840
+ await this._ensureConnected();
694
841
  const item = await this.findOne({ key: key });
695
842
  if (!item || !Array.isArray(item.value)) {
696
843
  return [];
697
844
  }
698
-
845
+
699
846
  // 处理负数索引
700
847
  let startIndex = start < 0 ? item.value.length + start : start;
701
848
  let endIndex = stop < 0 ? item.value.length + stop : stop;
702
-
849
+
703
850
  // 确保索引有效
704
851
  startIndex = Math.max(0, Math.min(startIndex, item.value.length - 1));
705
852
  endIndex = Math.max(startIndex, Math.min(endIndex, item.value.length - 1));
706
-
853
+
707
854
  return item.value.slice(startIndex, endIndex + 1);
708
855
  } catch (error) {
709
856
  $.log.error('[MongoDB] 列表范围查询失败:', error);
710
857
  return [];
711
858
  }
712
859
  }
713
-
860
+
714
861
  /**
715
862
  * @description Redis兼容API - 获取列表指定索引元素
716
863
  * @param {String} key 键名
@@ -719,25 +866,26 @@ class MongoDB extends eventEmitter {
719
866
  */
720
867
  async lindex(key, index) {
721
868
  try {
869
+ await this._ensureConnected();
722
870
  const item = await this.findOne({ key: key });
723
871
  if (!item || !Array.isArray(item.value)) {
724
872
  return null;
725
873
  }
726
-
874
+
727
875
  // 处理负数索引
728
876
  const realIndex = index < 0 ? item.value.length + index : index;
729
-
877
+
730
878
  if (realIndex < 0 || realIndex >= item.value.length) {
731
879
  return null;
732
880
  }
733
-
881
+
734
882
  return item.value[realIndex];
735
883
  } catch (error) {
736
884
  $.log.error('[MongoDB] 获取列表索引元素失败:', error);
737
885
  return null;
738
886
  }
739
887
  }
740
-
888
+
741
889
  /**
742
890
  * @description Redis兼容API - 设置列表指定索引元素
743
891
  * @param {String} key 键名
@@ -747,27 +895,28 @@ class MongoDB extends eventEmitter {
747
895
  */
748
896
  async lset(key, index, value) {
749
897
  try {
898
+ await this._ensureConnected();
750
899
  const item = await this.findOne({ key: key });
751
900
  if (!item || !Array.isArray(item.value)) {
752
901
  return false;
753
902
  }
754
-
903
+
755
904
  // 处理负数索引
756
905
  const realIndex = index < 0 ? item.value.length + index : index;
757
-
906
+
758
907
  if (realIndex < 0 || realIndex >= item.value.length) {
759
908
  return false;
760
909
  }
761
-
910
+
762
911
  item.value[realIndex] = value;
763
- await this.set({ key: key }, { value: item.value });
912
+ await this._set({ key: key }, { value: item.value });
764
913
  return true;
765
914
  } catch (error) {
766
915
  $.log.error('[MongoDB] 设置列表索引元素失败:', error);
767
916
  return false;
768
917
  }
769
918
  }
770
-
919
+
771
920
  /**
772
921
  * @description Redis兼容API - 删除列表元素
773
922
  * @param {String} key 键名
@@ -777,14 +926,15 @@ class MongoDB extends eventEmitter {
777
926
  */
778
927
  async lrem(key, count, value) {
779
928
  try {
929
+ await this._ensureConnected();
780
930
  const item = await this.findOne({ key: key });
781
931
  if (!item || !Array.isArray(item.value)) {
782
932
  return 0;
783
933
  }
784
-
934
+
785
935
  let list = [...item.value];
786
936
  let removedCount = 0;
787
-
937
+
788
938
  if (count > 0) {
789
939
  // 从头部删除count个等于value的元素
790
940
  for (let i = 0; i < list.length && removedCount < count; i++) {
@@ -808,18 +958,18 @@ class MongoDB extends eventEmitter {
808
958
  list = list.filter(item => JSON.stringify(item) !== JSON.stringify(value));
809
959
  removedCount = item.value.length - list.length;
810
960
  }
811
-
961
+
812
962
  if (removedCount > 0) {
813
- await this.set({ key: key }, { value: list });
963
+ await this._set({ key: key }, { value: list });
814
964
  }
815
-
965
+
816
966
  return removedCount;
817
967
  } catch (error) {
818
968
  $.log.error('[MongoDB] 删除列表元素失败:', error);
819
969
  return 0;
820
970
  }
821
971
  }
822
-
972
+
823
973
  /**
824
974
  * @description Redis兼容API - 裁剪列表
825
975
  * @param {String} key 键名
@@ -829,21 +979,22 @@ class MongoDB extends eventEmitter {
829
979
  */
830
980
  async ltrim(key, start, stop) {
831
981
  try {
982
+ await this._ensureConnected();
832
983
  const item = await this.findOne({ key: key });
833
984
  if (!item || !Array.isArray(item.value)) {
834
985
  return false;
835
986
  }
836
-
987
+
837
988
  // 使用lrange的逻辑获取裁剪后的列表
838
989
  const trimmed = await this.lrange(key, start, stop);
839
- await this.set({ key: key }, { value: trimmed });
990
+ await this._set({ key: key }, { value: trimmed });
840
991
  return true;
841
992
  } catch (error) {
842
993
  $.log.error('[MongoDB] 裁剪列表失败:', error);
843
994
  return false;
844
995
  }
845
996
  }
846
-
997
+
847
998
  /**
848
999
  * @description Redis兼容API - 列表长度
849
1000
  * @param {String} key 键名
@@ -851,6 +1002,7 @@ class MongoDB extends eventEmitter {
851
1002
  */
852
1003
  async llen(key) {
853
1004
  try {
1005
+ await this._ensureConnected();
854
1006
  const item = await this.findOne({ key: key });
855
1007
  if (!item || !Array.isArray(item.value)) {
856
1008
  return 0;
@@ -861,7 +1013,7 @@ class MongoDB extends eventEmitter {
861
1013
  return 0;
862
1014
  }
863
1015
  }
864
-
1016
+
865
1017
  /**
866
1018
  * @description Redis兼容API - 集合批量添加
867
1019
  * @param {String} key 键名
@@ -870,28 +1022,29 @@ class MongoDB extends eventEmitter {
870
1022
  */
871
1023
  async saddMulti(key, members) {
872
1024
  try {
1025
+ await this._ensureConnected();
873
1026
  const item = await this.findOne({ key: key });
874
1027
  let set = item && Array.isArray(item.value) ? [...new Set(item.value)] : [];
875
1028
  let addedCount = 0;
876
-
1029
+
877
1030
  members.forEach(member => {
878
1031
  if (!set.some(existing => JSON.stringify(existing) === JSON.stringify(member))) {
879
1032
  set.push(member);
880
1033
  addedCount++;
881
1034
  }
882
1035
  });
883
-
1036
+
884
1037
  if (addedCount > 0) {
885
- await this.add(key, set);
1038
+ await this._add(key, set);
886
1039
  }
887
-
1040
+
888
1041
  return addedCount;
889
1042
  } catch (error) {
890
1043
  $.log.error('[MongoDB] 集合并发添加失败:', error);
891
1044
  return 0;
892
1045
  }
893
1046
  }
894
-
1047
+
895
1048
  /**
896
1049
  * @description Redis兼容API - 集合批量删除
897
1050
  * @param {String} key 键名
@@ -900,30 +1053,31 @@ class MongoDB extends eventEmitter {
900
1053
  */
901
1054
  async sremMulti(key, members) {
902
1055
  try {
1056
+ await this._ensureConnected();
903
1057
  const item = await this.findOne({ key: key });
904
1058
  if (!item || !Array.isArray(item.value)) {
905
1059
  return 0;
906
1060
  }
907
-
1061
+
908
1062
  let set = [...new Set(item.value)];
909
1063
  const originalLength = set.length;
910
-
1064
+
911
1065
  // 创建要删除的值的字符串表示集合用于快速查找
912
1066
  const membersToRemove = new Set(members.map(m => JSON.stringify(m)));
913
1067
  set = set.filter(member => !membersToRemove.has(JSON.stringify(member)));
914
-
1068
+
915
1069
  const removedCount = originalLength - set.length;
916
1070
  if (removedCount > 0) {
917
- await this.add(key, set);
1071
+ await this._add(key, set);
918
1072
  }
919
-
1073
+
920
1074
  return removedCount;
921
1075
  } catch (error) {
922
1076
  $.log.error('[MongoDB] 集合并发删除失败:', error);
923
1077
  return 0;
924
1078
  }
925
1079
  }
926
-
1080
+
927
1081
  /**
928
1082
  * @description Redis兼容API - 集合差集
929
1083
  * @param {String} key1 第一个集合键
@@ -932,15 +1086,16 @@ class MongoDB extends eventEmitter {
932
1086
  */
933
1087
  async sdiff(key1, key2) {
934
1088
  try {
1089
+ await this._ensureConnected();
935
1090
  const item1 = await this.findOne({ key: key1 });
936
1091
  const item2 = await this.findOne({ key: key2 });
937
-
1092
+
938
1093
  const set1 = item1 && Array.isArray(item1.value) ? [...new Set(item1.value)] : [];
939
1094
  const set2 = item2 && Array.isArray(item2.value) ? [...new Set(item2.value)] : [];
940
-
1095
+
941
1096
  // 创建第二个集合值的字符串表示用于快速查找
942
1097
  const set2Str = new Set(set2.map(m => JSON.stringify(m)));
943
-
1098
+
944
1099
  // 找出在set1中但不在set2中的元素
945
1100
  return set1.filter(member => !set2Str.has(JSON.stringify(member)));
946
1101
  } catch (error) {
@@ -948,7 +1103,7 @@ class MongoDB extends eventEmitter {
948
1103
  return [];
949
1104
  }
950
1105
  }
951
-
1106
+
952
1107
  /**
953
1108
  * @description Redis兼容API - 集合交集
954
1109
  * @param {String} key1 第一个集合键
@@ -957,12 +1112,13 @@ class MongoDB extends eventEmitter {
957
1112
  */
958
1113
  async sinter(key1, key2) {
959
1114
  try {
1115
+ await this._ensureConnected();
960
1116
  const item1 = await this.findOne({ key: key1 });
961
1117
  const item2 = await this.findOne({ key: key2 });
962
-
1118
+
963
1119
  const set1 = item1 && Array.isArray(item1.value) ? [...new Set(item1.value)] : [];
964
1120
  const set2 = item2 && Array.isArray(item2.value) ? [...new Set(item2.value)] : [];
965
-
1121
+
966
1122
  // 创建较小集合的字符串表示用于快速查找,优化性能
967
1123
  let smallerSet, largerSet;
968
1124
  if (set1.length <= set2.length) {
@@ -972,9 +1128,9 @@ class MongoDB extends eventEmitter {
972
1128
  smallerSet = set2;
973
1129
  largerSet = set1;
974
1130
  }
975
-
1131
+
976
1132
  const largerSetStr = new Set(largerSet.map(m => JSON.stringify(m)));
977
-
1133
+
978
1134
  // 找出同时存在于两个集合中的元素
979
1135
  return smallerSet.filter(member => largerSetStr.has(JSON.stringify(member)));
980
1136
  } catch (error) {
@@ -982,7 +1138,7 @@ class MongoDB extends eventEmitter {
982
1138
  return [];
983
1139
  }
984
1140
  }
985
-
1141
+
986
1142
  /**
987
1143
  * @description Redis兼容API - 集合并集
988
1144
  * @param {String} key1 第一个集合键
@@ -991,31 +1147,32 @@ class MongoDB extends eventEmitter {
991
1147
  */
992
1148
  async sunion(key1, key2) {
993
1149
  try {
1150
+ await this._ensureConnected();
994
1151
  const item1 = await this.findOne({ key: key1 });
995
1152
  const item2 = await this.findOne({ key: key2 });
996
-
1153
+
997
1154
  const set1 = item1 && Array.isArray(item1.value) ? item1.value : [];
998
1155
  const set2 = item2 && Array.isArray(item2.value) ? item2.value : [];
999
-
1156
+
1000
1157
  // 合并并去重
1001
1158
  const combined = [...set1, ...set2];
1002
1159
  // 使用Map进行对象去重,基于JSON字符串表示
1003
1160
  const uniqueMap = new Map();
1004
-
1161
+
1005
1162
  combined.forEach(item => {
1006
1163
  const key = JSON.stringify(item);
1007
1164
  if (!uniqueMap.has(key)) {
1008
1165
  uniqueMap.set(key, item);
1009
1166
  }
1010
1167
  });
1011
-
1168
+
1012
1169
  return Array.from(uniqueMap.values());
1013
1170
  } catch (error) {
1014
1171
  $.log.error('[MongoDB] 集合并集失败:', error);
1015
1172
  return [];
1016
1173
  }
1017
1174
  }
1018
-
1175
+
1019
1176
  /**
1020
1177
  * @description Redis兼容API - 集合成员数量
1021
1178
  * @param {String} key 键名
@@ -1023,11 +1180,12 @@ class MongoDB extends eventEmitter {
1023
1180
  */
1024
1181
  async scard(key) {
1025
1182
  try {
1183
+ await this._ensureConnected();
1026
1184
  const item = await this.findOne({ key: key });
1027
1185
  if (!item || !Array.isArray(item.value)) {
1028
1186
  return 0;
1029
1187
  }
1030
-
1188
+
1031
1189
  // 使用Set去重并计算大小
1032
1190
  const uniqueItems = new Set(item.value.map(m => JSON.stringify(m)));
1033
1191
  return uniqueItems.size;
@@ -1036,7 +1194,7 @@ class MongoDB extends eventEmitter {
1036
1194
  return 0;
1037
1195
  }
1038
1196
  }
1039
-
1197
+
1040
1198
  /**
1041
1199
  * @description Redis兼容API - 检查是否是集合成员
1042
1200
  * @param {String} key 键名
@@ -1045,11 +1203,12 @@ class MongoDB extends eventEmitter {
1045
1203
  */
1046
1204
  async sismember(key, member) {
1047
1205
  try {
1206
+ await this._ensureConnected();
1048
1207
  const item = await this.findOne({ key: key });
1049
1208
  if (!item || !Array.isArray(item.value)) {
1050
1209
  return false;
1051
1210
  }
1052
-
1211
+
1053
1212
  // 检查是否存在相同的成员
1054
1213
  const memberStr = JSON.stringify(member);
1055
1214
  return item.value.some(m => JSON.stringify(m) === memberStr);
@@ -1058,26 +1217,31 @@ class MongoDB extends eventEmitter {
1058
1217
  return false;
1059
1218
  }
1060
1219
  }
1061
-
1220
+
1062
1221
  /**
1063
1222
  * @description Redis兼容API - 批量获取
1064
- * @param {Array} keys 键名数组
1065
- * @return {Promise<Object>} 键值对象
1223
+ * @param {...String} keys 键名列表
1224
+ * @return {Promise<Array>} 与键顺序对应的值数组,不存在返回null
1066
1225
  */
1067
- async mget(keys) {
1226
+ async mget(...keys) {
1068
1227
  try {
1069
- const results = await this.find({ key: { $in: keys } });
1228
+ await this._ensureConnected();
1229
+ // 确保keys是数组
1230
+ const keyArray = Array.isArray(keys[0]) ? keys[0] : keys;
1231
+ const results = await this.find({ key: { $in: keyArray } });
1070
1232
  const resultMap = {};
1071
1233
  results.forEach(item => {
1072
1234
  resultMap[item.key] = item.value;
1073
1235
  });
1074
- return resultMap;
1236
+
1237
+ // 返回与输入键顺序对应的数组,不存在的键对应位置返回null
1238
+ return keyArray.map(key => resultMap.hasOwnProperty(key) ? resultMap[key] : null);
1075
1239
  } catch (error) {
1076
1240
  $.log.error('[MongoDB] 批量获取失败:', error);
1077
- return {};
1241
+ return [];
1078
1242
  }
1079
1243
  }
1080
-
1244
+
1081
1245
  /**
1082
1246
  * @description Redis兼容API - 批量设置
1083
1247
  * @param {Object} keyValues 键值对象
@@ -1085,8 +1249,9 @@ class MongoDB extends eventEmitter {
1085
1249
  */
1086
1250
  async mset(keyValues) {
1087
1251
  try {
1252
+ await this._ensureConnected();
1088
1253
  for (const [key, value] of Object.entries(keyValues)) {
1089
- await this.add(key, value);
1254
+ await this._add(key, value);
1090
1255
  }
1091
1256
  return true;
1092
1257
  } catch (error) {
@@ -1094,7 +1259,7 @@ class MongoDB extends eventEmitter {
1094
1259
  return false;
1095
1260
  }
1096
1261
  }
1097
-
1262
+
1098
1263
  /**
1099
1264
  * @description Redis兼容API - 有序集合添加成员
1100
1265
  * @param {String} key 键名
@@ -1104,29 +1269,30 @@ class MongoDB extends eventEmitter {
1104
1269
  */
1105
1270
  async zadd(key, score, member) {
1106
1271
  try {
1272
+ await this._ensureConnected();
1107
1273
  const item = await this.findOne({ key: key });
1108
1274
  let sortedSet = item && Array.isArray(item.value) ? item.value : [];
1109
-
1275
+
1110
1276
  // 检查成员是否已存在,如果存在则更新分数
1111
1277
  const memberStr = JSON.stringify(member);
1112
1278
  const existingIndex = sortedSet.findIndex(item => JSON.stringify(item.member) === memberStr);
1113
-
1279
+
1114
1280
  if (existingIndex >= 0) {
1115
1281
  sortedSet[existingIndex].score = score;
1116
1282
  } else {
1117
1283
  sortedSet.push({ score, member });
1118
1284
  }
1119
-
1285
+
1120
1286
  // 按分数排序
1121
1287
  sortedSet.sort((a, b) => a.score - b.score);
1122
- await this.add(key, sortedSet);
1288
+ await this._add(key, sortedSet);
1123
1289
  return true;
1124
1290
  } catch (error) {
1125
1291
  $.log.error('[MongoDB] 有序集合添加成员失败:', error);
1126
1292
  return false;
1127
1293
  }
1128
1294
  }
1129
-
1295
+
1130
1296
  /**
1131
1297
  * @description Redis兼容API - 有序集合范围查询(按分数)
1132
1298
  * @param {String} key 键名
@@ -1136,11 +1302,12 @@ class MongoDB extends eventEmitter {
1136
1302
  */
1137
1303
  async zrangebyscore(key, min, max) {
1138
1304
  try {
1305
+ await this._ensureConnected();
1139
1306
  const item = await this.findOne({ key: key });
1140
1307
  if (!item || !Array.isArray(item.value)) {
1141
1308
  return [];
1142
1309
  }
1143
-
1310
+
1144
1311
  // 过滤分数范围内的成员
1145
1312
  return item.value
1146
1313
  .filter(item => item.score >= min && item.score <= max)
@@ -1150,7 +1317,7 @@ class MongoDB extends eventEmitter {
1150
1317
  return [];
1151
1318
  }
1152
1319
  }
1153
-
1320
+
1154
1321
  /**
1155
1322
  * @description Redis兼容API - 有序集合成员数量
1156
1323
  * @param {String} key 键名
@@ -1158,6 +1325,7 @@ class MongoDB extends eventEmitter {
1158
1325
  */
1159
1326
  async zcard(key) {
1160
1327
  try {
1328
+ await this._ensureConnected();
1161
1329
  const item = await this.findOne({ key: key });
1162
1330
  if (!item || !Array.isArray(item.value)) {
1163
1331
  return 0;
@@ -1168,7 +1336,7 @@ class MongoDB extends eventEmitter {
1168
1336
  return 0;
1169
1337
  }
1170
1338
  }
1171
-
1339
+
1172
1340
  /**
1173
1341
  * @description Redis兼容API - 有序集合删除成员
1174
1342
  * @param {String} key 键名
@@ -1177,26 +1345,27 @@ class MongoDB extends eventEmitter {
1177
1345
  */
1178
1346
  async zrem(key, member) {
1179
1347
  try {
1348
+ await this._ensureConnected();
1180
1349
  const item = await this.findOne({ key: key });
1181
1350
  if (!item || !Array.isArray(item.value)) {
1182
1351
  return 0;
1183
1352
  }
1184
-
1353
+
1185
1354
  const memberStr = JSON.stringify(member);
1186
1355
  const filtered = item.value.filter(item => JSON.stringify(item.member) !== memberStr);
1187
1356
  const removedCount = item.value.length - filtered.length;
1188
-
1357
+
1189
1358
  if (removedCount > 0) {
1190
- await this.add(key, filtered);
1359
+ await this._add(key, filtered);
1191
1360
  }
1192
-
1361
+
1193
1362
  return removedCount;
1194
1363
  } catch (error) {
1195
1364
  $.log.error('[MongoDB] 有序集合删除成员失败:', error);
1196
1365
  return 0;
1197
1366
  }
1198
1367
  }
1199
-
1368
+
1200
1369
  /**
1201
1370
  * @description Redis兼容API - 获取成员分数
1202
1371
  * @param {String} key 键名
@@ -1205,11 +1374,12 @@ class MongoDB extends eventEmitter {
1205
1374
  */
1206
1375
  async zscore(key, member) {
1207
1376
  try {
1377
+ await this._ensureConnected();
1208
1378
  const item = await this.findOne({ key: key });
1209
1379
  if (!item || !Array.isArray(item.value)) {
1210
1380
  return null;
1211
1381
  }
1212
-
1382
+
1213
1383
  const memberStr = JSON.stringify(member);
1214
1384
  const found = item.value.find(item => JSON.stringify(item.member) === memberStr);
1215
1385
  return found ? found.score : null;
@@ -1218,7 +1388,7 @@ class MongoDB extends eventEmitter {
1218
1388
  return null;
1219
1389
  }
1220
1390
  }
1221
-
1391
+
1222
1392
  /**
1223
1393
  * @description Redis兼容API - 列表弹出头部元素
1224
1394
  * @param {String} key 键名
@@ -1226,20 +1396,21 @@ class MongoDB extends eventEmitter {
1226
1396
  */
1227
1397
  async lpop(key) {
1228
1398
  try {
1399
+ await this._ensureConnected();
1229
1400
  const item = await this.findOne({ key: key });
1230
1401
  if (!item || !Array.isArray(item.value) || item.value.length === 0) {
1231
1402
  return null;
1232
1403
  }
1233
-
1404
+
1234
1405
  const popped = item.value.shift();
1235
- await this.set({ key: key }, { value: item.value });
1406
+ await this._set({ key: key }, { value: item.value });
1236
1407
  return popped;
1237
1408
  } catch (error) {
1238
1409
  $.log.error('[MongoDB] 列表弹出头部元素失败:', error);
1239
1410
  return null;
1240
1411
  }
1241
1412
  }
1242
-
1413
+
1243
1414
  /**
1244
1415
  * @description Redis兼容API - 列表弹出尾部元素
1245
1416
  * @param {String} key 键名
@@ -1247,20 +1418,21 @@ class MongoDB extends eventEmitter {
1247
1418
  */
1248
1419
  async rpop(key) {
1249
1420
  try {
1421
+ await this._ensureConnected();
1250
1422
  const item = await this.findOne({ key: key });
1251
1423
  if (!item || !Array.isArray(item.value) || item.value.length === 0) {
1252
1424
  return null;
1253
1425
  }
1254
-
1426
+
1255
1427
  const popped = item.value.pop();
1256
- await this.set({ key: key }, { value: item.value });
1428
+ await this._set({ key: key }, { value: item.value });
1257
1429
  return popped;
1258
1430
  } catch (error) {
1259
1431
  $.log.error('[MongoDB] 列表弹出尾部元素失败:', error);
1260
1432
  return null;
1261
1433
  }
1262
1434
  }
1263
-
1435
+
1264
1436
  /**
1265
1437
  * @description Redis兼容API - 获取集合所有成员
1266
1438
  * @param {String} key 键名
@@ -1268,11 +1440,12 @@ class MongoDB extends eventEmitter {
1268
1440
  */
1269
1441
  async smembers(key) {
1270
1442
  try {
1443
+ await this._ensureConnected();
1271
1444
  const item = await this.findOne({ key: key });
1272
1445
  if (!item || !Array.isArray(item.value)) {
1273
1446
  return [];
1274
1447
  }
1275
-
1448
+
1276
1449
  // 去重并返回
1277
1450
  const uniqueMap = new Map();
1278
1451
  item.value.forEach(member => {
@@ -1296,10 +1469,13 @@ class MongoDB extends eventEmitter {
1296
1469
  MongoDB.prototype.setConfig = function (cg) {
1297
1470
  var obj;
1298
1471
  if (typeof (cg) === "string") {
1299
- obj = cg.loadJson ? cg.loadJson(this.dir) : null;
1472
+ obj = cg.loadJson();
1300
1473
  } else if (cg) {
1301
1474
  obj = cg;
1302
1475
  }
1476
+ else {
1477
+ return;
1478
+ }
1303
1479
  if (obj) {
1304
1480
  $.push(this.config, obj);
1305
1481
  // 设置新配置后重新验证
@@ -1370,11 +1546,12 @@ MongoDB.prototype.close = async function () {
1370
1546
  };
1371
1547
 
1372
1548
  /**
1373
- * @description 创建数据表
1374
- * @param {Object} table 表名
1375
- * @return {Promise|Object} 执行结果
1376
- */
1377
- MongoDB.prototype.addTable = function (table) {
1549
+ * @description 创建数据表
1550
+ * @param {Object} table 表名
1551
+ * @return {Promise|Object} 执行结果
1552
+ */
1553
+ MongoDB.prototype.addTable = async function (table) {
1554
+ await this._ensureConnected();
1378
1555
  if (table) {
1379
1556
  this.table = table;
1380
1557
  } else {
@@ -1390,6 +1567,7 @@ MongoDB.prototype.addTable = function (table) {
1390
1567
  * @returns {Promise<Object>} 创建索引的结果
1391
1568
  */
1392
1569
  MongoDB.prototype.createIndex = async function (keys, options = {}) {
1570
+ await this._ensureConnected();
1393
1571
  try {
1394
1572
  if (!this.db || !this.table) {
1395
1573
  throw new Error('数据库未连接或未指定表名');
@@ -1411,6 +1589,7 @@ MongoDB.prototype.createIndex = async function (keys, options = {}) {
1411
1589
  * @returns {Promise<Object>} 创建索引的结果
1412
1590
  */
1413
1591
  MongoDB.prototype.createTTLIndex = async function (keys, expireAfterSeconds) {
1592
+ await this._ensureConnected();
1414
1593
  try {
1415
1594
  if (!this.db || !this.table) {
1416
1595
  throw new Error('数据库未连接或未指定表名');
@@ -1431,13 +1610,14 @@ MongoDB.prototype.createTTLIndex = async function (keys, expireAfterSeconds) {
1431
1610
  };
1432
1611
 
1433
1612
  /**
1434
- * @description 获取集合的所有索引
1435
- * @returns {Promise<Array>} 索引信息数组
1436
- */
1613
+ * @description 获取集合的所有索引
1614
+ * @returns {Promise<Array>} 索引信息数组
1615
+ */
1437
1616
  MongoDB.prototype.getIndexes = async function () {
1617
+ await this._ensureConnected();
1438
1618
  try {
1439
- if (!this.db || !this.table) {
1440
- throw new Error('数据库未连接或未指定表名');
1619
+ if (!this.table) {
1620
+ throw new Error('未指定表名');
1441
1621
  }
1442
1622
 
1443
1623
  $.log.info(`[MongoDB] 获取索引: ${this.table}`);
@@ -1454,9 +1634,7 @@ MongoDB.prototype.getIndexes = async function () {
1454
1634
  * @returns {Promise<Boolean>} 是否删除成功
1455
1635
  */
1456
1636
  MongoDB.prototype.dropIndex = async function (indexName) {
1457
- if (!this.conn || !this.db) {
1458
- throw new Error('数据库未连接');
1459
- }
1637
+ await this._ensureConnected();
1460
1638
  if (!this.table) {
1461
1639
  throw new Error('未指定表名');
1462
1640
  }
@@ -1478,9 +1656,7 @@ MongoDB.prototype.dropIndex = async function (indexName) {
1478
1656
  * @returns {Promise<Boolean>} 是否删除成功
1479
1657
  */
1480
1658
  MongoDB.prototype.dropTable = async function () {
1481
- if (!this.conn || !this.db) {
1482
- throw new Error('数据库未连接');
1483
- }
1659
+ await this._ensureConnected();
1484
1660
  if (!this.table) {
1485
1661
  throw new Error('未指定表名');
1486
1662
  }
@@ -1499,45 +1675,156 @@ MongoDB.prototype.dropTable = async function () {
1499
1675
  * @param {Object} obj 对象
1500
1676
  * @return {Promise|Object} 执行结果
1501
1677
  */
1502
- MongoDB.prototype.addObj = async function(obj) {
1678
+ MongoDB.prototype.addObj = async function (obj) {
1679
+ await this._ensureConnected();
1503
1680
  try {
1504
1681
  // 触发前置事件
1505
- this.emit('beforeInsert', { table: this.table, data: obj });
1506
-
1682
+ this.emit('addObj_before', { table: this.table, data: obj });
1683
+
1507
1684
  // 执行插入操作
1508
1685
  const result = await this.db.collection(this.table).insertOne(obj);
1509
-
1686
+
1510
1687
  // 触发后置事件
1511
- this.emit('afterInsert', { table: this.table, data: obj, result });
1512
-
1688
+ this.emit('addObj_after', { table: this.table, data: obj, result });
1689
+
1513
1690
  return result;
1514
1691
  } catch (error) {
1515
1692
  // 触发错误事件
1516
- this.emit('insertError', { table: this.table, data: obj, error });
1693
+ this.emit('addObj_error', { table: this.table, data: obj, error });
1517
1694
  throw error;
1518
1695
  }
1519
1696
  };
1520
1697
 
1698
+ /**
1699
+ * @description Redis兼容API - 根据键获取值
1700
+ * @param {String} key 键名
1701
+ * @return {Promise<any|null>} 存储的值,如果不存在则返回null
1702
+ */
1703
+ MongoDB.prototype.get = async function (key) {
1704
+ await this._ensureConnected();
1705
+ try {
1706
+ const result = await this.db.collection(this.table).findOne({ key: key });
1707
+ return result ? result.value : null;
1708
+ } catch (error) {
1709
+ $.log.error(`[MongoDB] 获取键值失败: ${error.message}`);
1710
+ return null;
1711
+ }
1712
+ };
1713
+
1714
+ /**
1715
+ * @description Redis兼容API - 删除键
1716
+ * @param {String} key 键名
1717
+ * @return {Promise<Boolean>} 是否删除成功
1718
+ */
1719
+ MongoDB.prototype.del = async function (key) {
1720
+ await this._ensureConnected();
1721
+ try {
1722
+ // 触发前置事件
1723
+ this.emit('del_before', { table: this.table, key: key });
1724
+
1725
+ const result = await this.db.collection(this.table).deleteOne({ key: key });
1726
+
1727
+ // 触发后置事件
1728
+ this.emit('del_after', { table: this.table, key: key, result });
1729
+
1730
+ return result.deletedCount > 0;
1731
+ } catch (error) {
1732
+ // 触发错误事件
1733
+ this.emit('del_error', { table: this.table, key: key, error });
1734
+ $.log.error(`[MongoDB] 删除键失败: ${error.message}`);
1735
+ return false;
1736
+ }
1737
+ };
1738
+
1739
+ /**
1740
+ * @description Redis兼容API - 添加键值对
1741
+ * @param {String} key 键名
1742
+ * @param {any} value 值
1743
+ * @return {Promise<Boolean>} 是否添加成功(如果键已存在则返回false)
1744
+ */
1745
+ MongoDB.prototype.add = async function (key, value) {
1746
+ await this._ensureConnected();
1747
+ try {
1748
+ // 触发前置事件 - 无论键是否存在都触发
1749
+ this.emit('add_before', { table: this.table, key: key, value: value });
1750
+
1751
+ // 检查键是否已存在
1752
+ const exists = await this.db.collection(this.table).findOne({ key: key });
1753
+ if (exists) {
1754
+ // 键已存在时触发后置事件,但返回false
1755
+ this.emit('add_after', { table: this.table, key: key, value: value, result: null, exists: true });
1756
+ return false;
1757
+ }
1758
+
1759
+ const data = { key: key, value: value };
1760
+
1761
+ // 添加键值对
1762
+ const result = await this.db.collection(this.table).insertOne(data);
1763
+
1764
+ // 触发后置事件
1765
+ this.emit('add_after', { table: this.table, key: key, value: value, result, exists: false });
1766
+
1767
+ return result.acknowledged;
1768
+ } catch (error) {
1769
+ // 触发错误事件
1770
+ this.emit('add_error', { table: this.table, key: key, value: value, error });
1771
+ $.log.error(`[MongoDB] 添加键值失败: ${error.message}`);
1772
+ return false;
1773
+ }
1774
+ };
1775
+
1776
+ /**
1777
+ * @description Redis兼容API - 设置键值对
1778
+ * @param {String} key 键名
1779
+ * @param {any} value 值
1780
+ * @return {Promise<Boolean>} 是否设置成功
1781
+ */
1782
+ MongoDB.prototype.set = async function (key, value) {
1783
+ await this._ensureConnected();
1784
+ try {
1785
+ // 触发前置事件
1786
+ this.emit('set_before', { table: this.table, key: key, value: value });
1787
+
1788
+ // 更新或插入键值对
1789
+ const result = await this.db.collection(this.table).updateOne(
1790
+ { key: key },
1791
+ { $set: { value: value } },
1792
+ { upsert: true }
1793
+ );
1794
+
1795
+ // 触发后置事件
1796
+ this.emit('set_after', { table: this.table, key: key, value: value, result });
1797
+
1798
+ return result.acknowledged;
1799
+ } catch (error) {
1800
+ // 触发错误事件
1801
+ this.emit('set_error', { table: this.table, key: key, value: value, error });
1802
+ $.log.error(`[MongoDB] 设置键值失败: ${error.message}`);
1803
+ return false;
1804
+ }
1805
+ };
1806
+
1521
1807
  /**
1522
1808
  * @description 增加多条缓存
1523
1809
  * @param {Array} list 对象数组
1524
1810
  * @return {Promise|Object} 执行结果
1525
1811
  */
1526
- MongoDB.prototype.addList = async function(list) {
1812
+ MongoDB.prototype.addList = async function (list) {
1813
+ await this._ensureConnected();
1527
1814
  try {
1528
1815
  // 触发前置事件
1529
- this.emit('beforeInsertMany', { table: this.table, data: list });
1530
-
1816
+ this.emit('addList_before', { table: this.table, data: list });
1817
+
1531
1818
  // 执行插入操作
1532
1819
  const result = await this.db.collection(this.table).insertMany(list);
1533
-
1820
+
1534
1821
  // 触发后置事件
1535
- this.emit('afterInsertMany', { table: this.table, data: list, result });
1536
-
1822
+ this.emit('addList_after', { table: this.table, data: list, result });
1823
+
1537
1824
  return result;
1538
1825
  } catch (error) {
1539
1826
  // 触发错误事件
1540
- this.emit('insertManyError', { table: this.table, data: list, error });
1827
+ this.emit('addList_error', { table: this.table, data: list, error });
1541
1828
  throw error;
1542
1829
  }
1543
1830
  };
@@ -1547,24 +1834,25 @@ MongoDB.prototype.addList = async function(list) {
1547
1834
  * @param {Object|String} query 查询条件对象或键名
1548
1835
  * @return {Promise|Object} 执行结果
1549
1836
  */
1550
- MongoDB.prototype.del = async function(query) {
1837
+ MongoDB.prototype.delete = async function (query) {
1838
+ await this._ensureConnected();
1551
1839
  try {
1552
1840
  // 如果query是字符串,则作为键名处理
1553
1841
  const safeQuery = typeof query === 'string' ? { key: query } : query;
1554
-
1842
+
1555
1843
  // 触发前置事件
1556
- this.emit('beforeDelete', { table: this.table, query: safeQuery });
1557
-
1844
+ this.emit('delete_before', { table: this.table, query: safeQuery });
1845
+
1558
1846
  // 执行删除操作
1559
1847
  const result = await this.db.collection(this.table).deleteMany(safeQuery);
1560
-
1848
+
1561
1849
  // 触发后置事件
1562
- this.emit('afterDelete', { table: this.table, query: safeQuery, result });
1563
-
1850
+ this.emit('delete_after', { table: this.table, query: safeQuery, result });
1851
+
1564
1852
  return result;
1565
1853
  } catch (error) {
1566
1854
  // 触发错误事件
1567
- this.emit('deleteError', { table: this.table, query, error });
1855
+ this.emit('delete_error', { table: this.table, query, error });
1568
1856
  throw error;
1569
1857
  }
1570
1858
  };
@@ -1576,11 +1864,12 @@ MongoDB.prototype.del = async function(query) {
1576
1864
  * @param {Object} options 附加选项
1577
1865
  * @return {Promise|Object} 执行结果
1578
1866
  */
1579
- MongoDB.prototype.set = async function(query, body, options = {}) {
1867
+ MongoDB.prototype.setting = async function (query, body, options = {}) {
1868
+ await this._ensureConnected();
1580
1869
  try {
1581
1870
  // 处理Redis兼容模式:如果query是字符串,则将query作为键名
1582
1871
  const safeQuery = typeof query === 'string' ? { key: query } : query;
1583
-
1872
+
1584
1873
  // 默认使用$set操作符进行部分更新
1585
1874
  let updateBody;
1586
1875
  if (typeof query === 'string') {
@@ -1591,25 +1880,25 @@ MongoDB.prototype.set = async function(query, body, options = {}) {
1591
1880
  } else {
1592
1881
  updateBody = body;
1593
1882
  }
1594
-
1883
+
1595
1884
  // 默认更新多条
1596
1885
  const updateOptions = Object.assign({ multi: true }, options);
1597
-
1886
+
1598
1887
  // 触发前置事件
1599
- this.emit('beforeUpdate', { table: this.table, query: safeQuery, update: updateBody, options: updateOptions });
1600
-
1888
+ this.emit('setting_before', { table: this.table, query: safeQuery, update: updateBody, options: updateOptions });
1889
+
1601
1890
  // 执行更新操作
1602
1891
  const result = await this.db.collection(this.table).updateMany(safeQuery, updateBody, updateOptions);
1603
-
1892
+
1604
1893
  // 触发后置事件
1605
- this.emit('afterUpdate', { table: this.table, query: safeQuery, update: updateBody, options: updateOptions, result });
1606
-
1894
+ this.emit('setting_after', { table: this.table, query: safeQuery, update: updateBody, options: updateOptions, result });
1895
+
1607
1896
  // Redis兼容模式返回布尔值,否则返回完整结果
1608
1897
  return typeof query === 'string' ? result.modifiedCount > 0 : result;
1609
1898
  } catch (error) {
1610
1899
  // 触发错误事件
1611
- this.emit('updateError', { table: this.table, query, update: body, options, error });
1612
-
1900
+ this.emit('setting_error', { table: this.table, query, update: body, options, error });
1901
+
1613
1902
  // Redis兼容模式返回布尔值
1614
1903
  return typeof query === 'string' ? false : null;
1615
1904
  }
@@ -1622,6 +1911,7 @@ MongoDB.prototype.set = async function(query, body, options = {}) {
1622
1911
  * @return {Promise|Array} 查询结果数组
1623
1912
  */
1624
1913
  MongoDB.prototype.find = async function (query, options = {}) {
1914
+ await this._ensureConnected();
1625
1915
  try {
1626
1916
  // 安全处理查询条件,避免注入
1627
1917
  const safeQuery = this._sanitizeQuery(query);
@@ -1640,6 +1930,7 @@ MongoDB.prototype.find = async function (query, options = {}) {
1640
1930
  * @return {Promise<Object|null>} 查询结果
1641
1931
  */
1642
1932
  MongoDB.prototype.findOne = async function (query, options = {}) {
1933
+ await this._ensureConnected();
1643
1934
  try {
1644
1935
  const safeQuery = this._sanitizeQuery(query);
1645
1936
  return await this.db.collection(this.table).findOne(safeQuery, options);
@@ -1655,6 +1946,7 @@ MongoDB.prototype.findOne = async function (query, options = {}) {
1655
1946
  * @return {Promise<Number>} 文档数量
1656
1947
  */
1657
1948
  MongoDB.prototype.count = async function (query = {}) {
1949
+ await this._ensureConnected();
1658
1950
  try {
1659
1951
  const safeQuery = this._sanitizeQuery(query);
1660
1952
  return await this.db.collection(this.table).countDocuments(safeQuery);
@@ -1691,6 +1983,7 @@ MongoDB.prototype._sanitizeQuery = function (query) {
1691
1983
  * @return {Promise<Object>} 会话对象
1692
1984
  */
1693
1985
  MongoDB.prototype.startTransaction = async function () {
1986
+ await this._ensureConnected();
1694
1987
  try {
1695
1988
  const session = this.conn.startSession();
1696
1989
  session.startTransaction();
@@ -1749,16 +2042,16 @@ if (!$.pool.mongoDB) {
1749
2042
  /**
1750
2043
  * @description MongoDB管理器,用于创建缓存
1751
2044
  * @param {String} scope 作用域
1752
- * @param {String} dir 当前路径
2045
+ * @param {Object} config 配置参数
1753
2046
  * @return {Object} 返回一个MongoDB类实例
1754
2047
  */
1755
- function mongoDB_admin(scope, dir) {
2048
+ function mongodb_admin(scope, config) {
1756
2049
  if (!scope) {
1757
- scope = ($.val && $.val.scope) || 'default';
2050
+ scope = 'sys';
1758
2051
  }
1759
2052
  var obj = $.pool.mongoDB[scope];
1760
2053
  if (!obj) {
1761
- $.pool.mongoDB[scope] = new MongoDB(scope, dir);
2054
+ $.pool.mongoDB[scope] = new MongoDB(scope, config);
1762
2055
  obj = $.pool.mongoDB[scope];
1763
2056
  }
1764
2057
  return obj;
@@ -1767,4 +2060,4 @@ function mongoDB_admin(scope, dir) {
1767
2060
  /**
1768
2061
  * @module 导出MongoDB管理器
1769
2062
  */
1770
- exports.mongoDB_admin = mongoDB_admin;
2063
+ exports.mongodb_admin = mongodb_admin;