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