mm_mongodb 1.4.6 → 1.4.7

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