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/README.md +23 -2
- package/compatibility_table.md +101 -64
- package/index.js +486 -194
- package/package.json +1 -1
- package/test2.js +22 -14
- package/test_redis_api.js +66 -0
- package/cache.js +0 -2866
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
613
|
+
async _set(key, value) {
|
|
487
614
|
try {
|
|
615
|
+
await this._ensureConnected();
|
|
488
616
|
// 直接使用已有的add方法,它已正确处理查询条件格式
|
|
489
|
-
return await this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 {
|
|
1065
|
-
* @return {Promise<
|
|
1224
|
+
* @param {...String} keys 键名列表
|
|
1225
|
+
* @return {Promise<Array>} 与键顺序对应的值数组,不存在返回null
|
|
1066
1226
|
*/
|
|
1067
|
-
async mget(keys) {
|
|
1227
|
+
async mget(...keys) {
|
|
1068
1228
|
try {
|
|
1069
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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
|
-
|
|
1435
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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.
|
|
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('
|
|
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('
|
|
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('
|
|
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.
|
|
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('
|
|
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('
|
|
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('
|
|
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
|
*/
|