@keyv/mongo 3.1.0 → 6.0.0-alpha.2

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 CHANGED
@@ -11,6 +11,35 @@ MongoDB storage adapter for [Keyv](https://github.com/jaredwray/keyv).
11
11
 
12
12
  Uses TTL indexes to automatically remove expired documents. However [MongoDB doesn't guarantee data will be deleted immediately upon expiration](https://docs.mongodb.com/manual/core/index-ttl/#timing-of-the-delete-operation), so expiry dates are revalidated in Keyv.
13
13
 
14
+ ## Table of Contents
15
+
16
+ - [Install](#install)
17
+ - [Usage](#usage)
18
+ - [Constructor Options](#constructor-options)
19
+ - [Properties](#properties)
20
+ - [url](#url)
21
+ - [collection](#collection)
22
+ - [namespace](#namespace)
23
+ - [useGridFS](#usegridfs)
24
+ - [db](#db)
25
+ - [readPreference](#readpreference)
26
+ - [Methods](#methods)
27
+ - [set](#set)
28
+ - [setMany](#setmany)
29
+ - [get](#get)
30
+ - [getMany](#getmany)
31
+ - [has](#has)
32
+ - [hasMany](#hasmany)
33
+ - [delete](#delete)
34
+ - [deleteMany](#deletemany)
35
+ - [clear](#clear)
36
+ - [iterator](#iterator)
37
+ - [disconnect](#disconnect)
38
+ - [clearExpired](#clearexpired)
39
+ - [clearUnusedFor](#clearunusedfor)
40
+ - [Migration from v3 to v6](#migration-from-v3-to-v6)
41
+ - [License](#license)
42
+
14
43
  ## Install
15
44
 
16
45
  ```shell
@@ -35,6 +64,498 @@ e.g:
35
64
  const keyv = new Keyv('mongodb://user:pass@localhost:27017/dbname', { collection: 'cache' });
36
65
  ```
37
66
 
67
+ You can also use the `createKeyv` helper function to create a `Keyv` instance with `KeyvMongo` as the store:
68
+
69
+ ```js
70
+ import { createKeyv } from '@keyv/mongo';
71
+
72
+ const keyv = createKeyv('mongodb://user:pass@localhost:27017/dbname');
73
+ ```
74
+
75
+ ## Constructor Options
76
+
77
+ The `KeyvMongo` constructor accepts a connection URI string or an options object:
78
+
79
+ ```js
80
+ // With URI string
81
+ const store = new KeyvMongo('mongodb://user:pass@localhost:27017/dbname');
82
+
83
+ // With options object
84
+ const store = new KeyvMongo({
85
+ url: 'mongodb://user:pass@localhost:27017/dbname',
86
+ collection: 'cache',
87
+ db: 'mydb',
88
+ useGridFS: false,
89
+ });
90
+
91
+ // With URI string and additional options
92
+ const store = new KeyvMongo('mongodb://user:pass@localhost:27017/dbname', { collection: 'cache' });
93
+ ```
94
+
95
+ | Option | Type | Default | Description |
96
+ |---|---|---|---|
97
+ | `url` | `string` | `'mongodb://127.0.0.1:27017'` | MongoDB connection URI |
98
+ | `collection` | `string` | `'keyv'` | Collection name for storage |
99
+ | `namespace` | `string \| undefined` | `undefined` | Namespace prefix for keys |
100
+ | `useGridFS` | `boolean` | `false` | Whether to use GridFS for storing values |
101
+ | `db` | `string \| undefined` | `undefined` | Database name |
102
+ | `readPreference` | `ReadPreference \| undefined` | `undefined` | MongoDB read preference for GridFS operations |
103
+
104
+ Any additional options are passed through to the MongoDB driver as `MongoClientOptions`.
105
+
106
+ ## Properties
107
+
108
+ Most configuration options are exposed as properties with getters and setters on the `KeyvMongo` instance. You can read or update them after construction. Some properties like `useGridFS` are read-only and can only be set via the constructor.
109
+
110
+ ### url
111
+
112
+ Get or set the MongoDB connection URI.
113
+
114
+ - Type: `string`
115
+ - Default: `'mongodb://127.0.0.1:27017'`
116
+
117
+ ```js
118
+ const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
119
+ console.log(store.url); // 'mongodb://user:pass@localhost:27017/dbname'
120
+ ```
121
+
122
+ ### collection
123
+
124
+ Get or set the collection name used for storage.
125
+
126
+ - Type: `string`
127
+ - Default: `'keyv'`
128
+
129
+ ```js
130
+ const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
131
+ console.log(store.collection); // 'keyv'
132
+ store.collection = 'cache';
133
+ ```
134
+
135
+ ### namespace
136
+
137
+ Get or set the namespace for the adapter. Used for key prefixing and scoping operations like `clear()`.
138
+
139
+ - Type: `string | undefined`
140
+ - Default: `undefined`
141
+
142
+ ```js
143
+ const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
144
+ store.namespace = 'my-namespace';
145
+ console.log(store.namespace); // 'my-namespace'
146
+ ```
147
+
148
+ ### useGridFS
149
+
150
+ Get whether GridFS is used for storing values. When enabled, values are stored using MongoDB's GridFS specification, which is useful for storing large files. This property is read-only and can only be set via the constructor, because the connection shape differs between GridFS and standard modes.
151
+
152
+ - Type: `boolean`
153
+ - Default: `false`
154
+ - Read-only (set via constructor only)
155
+
156
+ ```js
157
+ const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname', useGridFS: true });
158
+ console.log(store.useGridFS); // true
159
+ ```
160
+
161
+ ### db
162
+
163
+ Get or set the database name for the MongoDB connection.
164
+
165
+ - Type: `string | undefined`
166
+ - Default: `undefined`
167
+
168
+ ```js
169
+ const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017', db: 'mydb' });
170
+ console.log(store.db); // 'mydb'
171
+ ```
172
+
173
+ ### readPreference
174
+
175
+ Get or set the MongoDB read preference for GridFS operations.
176
+
177
+ - Type: `ReadPreference | undefined`
178
+ - Default: `undefined`
179
+
180
+ ```js
181
+ import { ReadPreference } from 'mongodb';
182
+
183
+ const store = new KeyvMongo({
184
+ url: 'mongodb://user:pass@localhost:27017/dbname',
185
+ useGridFS: true,
186
+ readPreference: ReadPreference.SECONDARY,
187
+ });
188
+ console.log(store.readPreference); // ReadPreference.SECONDARY
189
+ ```
190
+
191
+ ## Methods
192
+
193
+ ### set
194
+
195
+ `set(key, value, ttl?)` - Set a value in the store.
196
+
197
+ - `key` *(string)* - The key to set.
198
+ - `value` *(any)* - The value to store.
199
+ - `ttl` *(number, optional)* - Time to live in milliseconds. If specified, the key will expire after this duration.
200
+ - Returns: `Promise<void>`
201
+
202
+ ```js
203
+ const store = new KeyvMongo('mongodb://localhost:27017');
204
+ const keyv = new Keyv({ store });
205
+
206
+ await keyv.set('foo', 'bar');
207
+ await keyv.set('foo', 'bar', 5000); // expires in 5 seconds
208
+ ```
209
+
210
+ ### setMany
211
+
212
+ `setMany(entries)` - Set multiple values in the store at once.
213
+
214
+ - `entries` *(Array<{ key: string, value: any, ttl?: number }>)* - Array of entries to set. Each entry has a `key`, `value`, and optional `ttl` in milliseconds.
215
+ - Returns: `Promise<void>`
216
+
217
+ In standard mode, uses a single MongoDB `bulkWrite` operation for efficiency. In GridFS mode, each entry is set individually in parallel.
218
+
219
+ ```js
220
+ const store = new KeyvMongo('mongodb://localhost:27017');
221
+ const keyv = new Keyv({ store });
222
+
223
+ await keyv.set([
224
+ { key: 'key1', value: 'value1' },
225
+ { key: 'key2', value: 'value2', ttl: 5000 },
226
+ ]);
227
+ ```
228
+
229
+ ### get
230
+
231
+ `get(key)` - Get a value from the store.
232
+
233
+ - `key` *(string)* - The key to retrieve.
234
+ - Returns: `Promise<any>` - The stored value, or `undefined` if the key does not exist.
235
+
236
+ In GridFS mode, `get` also updates the `lastAccessed` timestamp on the file, which is used by `clearUnusedFor`.
237
+
238
+ ```js
239
+ const store = new KeyvMongo('mongodb://localhost:27017');
240
+ const keyv = new Keyv({ store });
241
+
242
+ await keyv.set('foo', 'bar');
243
+ const value = await keyv.get('foo');
244
+ console.log(value); // 'bar'
245
+
246
+ const missing = await keyv.get('nonexistent');
247
+ console.log(missing); // undefined
248
+ ```
249
+
250
+ ### getMany
251
+
252
+ `getMany(keys)` - Get multiple values from the store at once.
253
+
254
+ - `keys` *(string[])* - Array of keys to retrieve.
255
+ - Returns: `Promise<Array<any>>` - Array of values in the same order as the input keys. Missing keys return `undefined` at their position.
256
+
257
+ In standard mode, uses a single MongoDB query with the `$in` operator for efficiency. In GridFS mode, each key is fetched individually.
258
+
259
+ ```js
260
+ const store = new KeyvMongo('mongodb://localhost:27017');
261
+ const keyv = new Keyv({ store });
262
+
263
+ await keyv.set('key1', 'value1');
264
+ await keyv.set('key2', 'value2');
265
+
266
+ const values = await keyv.get(['key1', 'key2', 'key3']);
267
+ console.log(values); // ['value1', 'value2', undefined]
268
+ ```
269
+
270
+ ### has
271
+
272
+ `has(key)` - Check if a key exists in the store.
273
+
274
+ - `key` *(string)* - The key to check.
275
+ - Returns: `Promise<boolean>` - `true` if the key exists, `false` otherwise.
276
+
277
+ ```js
278
+ const store = new KeyvMongo('mongodb://localhost:27017');
279
+ const keyv = new Keyv({ store });
280
+
281
+ await keyv.set('foo', 'bar');
282
+ console.log(await keyv.has('foo')); // true
283
+ console.log(await keyv.has('nonexistent')); // false
284
+ ```
285
+
286
+ ### hasMany
287
+
288
+ `hasMany(keys)` - Check if multiple keys exist in the store at once.
289
+
290
+ - `keys` *(string[])* - Array of keys to check.
291
+ - Returns: `Promise<boolean[]>` - Array of booleans in the same order as the input keys.
292
+
293
+ Uses a single MongoDB query with the `$in` operator for efficiency in both standard and GridFS modes.
294
+
295
+ ```js
296
+ const store = new KeyvMongo('mongodb://localhost:27017');
297
+ const keyv = new Keyv({ store });
298
+
299
+ await keyv.set('key1', 'value1');
300
+ await keyv.set('key2', 'value2');
301
+
302
+ const results = await keyv.has(['key1', 'key2', 'key3']);
303
+ console.log(results); // [true, true, false]
304
+ ```
305
+
306
+ ### delete
307
+
308
+ `delete(key)` - Delete a key from the store.
309
+
310
+ - `key` *(string)* - The key to delete.
311
+ - Returns: `Promise<boolean>` - `true` if the key was deleted, `false` if the key was not found.
312
+
313
+ ```js
314
+ const store = new KeyvMongo('mongodb://localhost:27017');
315
+ const keyv = new Keyv({ store });
316
+
317
+ await keyv.set('foo', 'bar');
318
+ console.log(await keyv.delete('foo')); // true
319
+ console.log(await keyv.delete('nonexistent')); // false
320
+ ```
321
+
322
+ ### deleteMany
323
+
324
+ `deleteMany(keys)` - Delete multiple keys from the store at once.
325
+
326
+ - `keys` *(string[])* - Array of keys to delete.
327
+ - Returns: `Promise<boolean>` - `true` if any keys were deleted, `false` if none were found.
328
+
329
+ In standard mode, uses a single MongoDB query with the `$in` operator. In GridFS mode, all matching files are found and deleted in parallel.
330
+
331
+ ```js
332
+ const store = new KeyvMongo('mongodb://localhost:27017');
333
+ const keyv = new Keyv({ store });
334
+
335
+ await keyv.set('key1', 'value1');
336
+ await keyv.set('key2', 'value2');
337
+
338
+ console.log(await keyv.delete(['key1', 'key2', 'key3'])); // true
339
+ ```
340
+
341
+ ### clear
342
+
343
+ `clear()` - Delete all keys in the current namespace.
344
+
345
+ - Returns: `Promise<void>`
346
+
347
+ Only keys matching the current namespace are removed. If no namespace is set, all keys with an empty namespace are cleared.
348
+
349
+ ```js
350
+ const store = new KeyvMongo('mongodb://localhost:27017');
351
+ const keyv = new Keyv({ store, namespace: 'my-namespace' });
352
+
353
+ await keyv.set('key1', 'value1');
354
+ await keyv.set('key2', 'value2');
355
+
356
+ await keyv.clear(); // removes all keys in 'my-namespace'
357
+ ```
358
+
359
+ ### iterator
360
+
361
+ `iterator(namespace?)` - Iterate over all key-value pairs in the store.
362
+
363
+ - `namespace` *(string, optional)* - The namespace to iterate over. When used through Keyv, the namespace is passed automatically from the Keyv instance.
364
+ - Returns: `AsyncGenerator<[string, any]>` - An async generator yielding `[key, value]` pairs.
365
+
366
+ When used through Keyv, the namespace prefix is stripped from keys automatically.
367
+
368
+ ```js
369
+ const store = new KeyvMongo('mongodb://localhost:27017');
370
+ const keyv = new Keyv({ store, namespace: 'ns' });
371
+
372
+ await keyv.set('key1', 'value1');
373
+ await keyv.set('key2', 'value2');
374
+
375
+ for await (const [key, value] of keyv.iterator()) {
376
+ console.log(key, value); // 'key1' 'value1', 'key2' 'value2'
377
+ }
378
+ ```
379
+
380
+ ### disconnect
381
+
382
+ `disconnect()` - Close the MongoDB connection.
383
+
384
+ - Returns: `Promise<void>`
385
+
386
+ ```js
387
+ const store = new KeyvMongo('mongodb://localhost:27017');
388
+ const keyv = new Keyv({ store });
389
+
390
+ // ... use the store ...
391
+
392
+ await keyv.disconnect();
393
+ ```
394
+
395
+ ### clearExpired
396
+
397
+ `clearExpired()` - Remove all expired files from GridFS. This method only works in GridFS mode and is a no-op that returns `false` in standard mode.
398
+
399
+ - Returns: `Promise<boolean>` - `true` if running in GridFS mode, `false` otherwise.
400
+
401
+ This is useful for manual cleanup of expired GridFS files, since GridFS does not support MongoDB TTL indexes.
402
+
403
+ ```js
404
+ const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
405
+
406
+ await store.set('temp', 'data', 1000); // expires in 1 second
407
+
408
+ // After expiration...
409
+ await store.clearExpired(); // removes expired GridFS files
410
+ ```
411
+
412
+ ### clearUnusedFor
413
+
414
+ `clearUnusedFor(seconds)` - Remove all GridFS files that have not been accessed for the specified duration. This method only works in GridFS mode and is a no-op that returns `false` in standard mode.
415
+
416
+ - `seconds` *(number)* - The number of seconds of inactivity after which files should be removed.
417
+ - Returns: `Promise<boolean>` - `true` if running in GridFS mode, `false` otherwise.
418
+
419
+ The `lastAccessed` timestamp is updated each time a file is read via `get`.
420
+
421
+ ```js
422
+ const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
423
+
424
+ await store.set('foo', 'bar');
425
+
426
+ // Remove files not accessed in the last hour
427
+ await store.clearUnusedFor(3600);
428
+ ```
429
+
430
+ ## Migration from v3 to v6
431
+
432
+ `@keyv/mongo` is jumping from v3 to v6 because the entire Keyv monorepo is now unified under a single version number. This approach, similar to what other popular open source projects do, keeps all `@keyv/*` packages in sync and makes it easier to reason about compatibility across the ecosystem.
433
+
434
+ ### Breaking Changes
435
+
436
+ #### MongoDB Driver Upgraded to v7
437
+
438
+ The `mongodb` dependency has been upgraded from `^6.x` to `^7.0.0`. Review the [MongoDB Node.js Driver v7 release notes](https://github.com/mongodb/node-mongodb-native/releases/tag/v7.0.0) for any breaking changes that may affect your application.
439
+
440
+ #### Event Handling: EventEmitter Replaced with Hookified
441
+
442
+ `KeyvMongo` no longer extends Node.js `EventEmitter`. It now extends `Hookified`, which provides hook-based event management.
443
+
444
+ ```js
445
+ // v3 - EventEmitter
446
+ const store = new KeyvMongo('mongodb://localhost:27017');
447
+ store.on('error', err => console.error(err));
448
+
449
+ // v6 - Hookified (same usage for basic events)
450
+ const store = new KeyvMongo('mongodb://localhost:27017');
451
+ store.on('error', err => console.error(err));
452
+ ```
453
+
454
+ For most use cases the `.on()` API is the same, but if you relied on EventEmitter-specific methods like `.listenerCount()`, `.rawListeners()`, or `.prependListener()`, check the [Hookified documentation](https://github.com/jaredwray/hookified) for equivalents.
455
+
456
+ #### `useGridFS` is Now Read-Only
457
+
458
+ The `useGridFS` property can no longer be changed after construction. The connection shape differs between GridFS and standard modes, so this must be set at construction time.
459
+
460
+ ```js
461
+ // v3 - Could change after instantiation
462
+ const store = new KeyvMongo('mongodb://localhost:27017');
463
+ store.useGridFS = true; // worked in v3
464
+
465
+ // v6 - Must set at construction
466
+ const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
467
+ console.log(store.useGridFS); // true (read-only)
468
+ ```
469
+
470
+ #### Property Access Changed from `opts` to Direct Getters/Setters
471
+
472
+ Properties are no longer accessed through an `opts` object. Use the direct getters and setters on the instance instead.
473
+
474
+ ```js
475
+ // v3
476
+ store.opts.url;
477
+ store.opts.collection = 'cache';
478
+
479
+ // v6
480
+ store.url;
481
+ store.collection = 'cache';
482
+ ```
483
+
484
+ #### `ttlSupport` Property Removed
485
+
486
+ The `ttlSupport` property has been removed. If your code checks for TTL support on the adapter, remove those checks.
487
+
488
+ #### Namespace Index Change
489
+
490
+ The unique index on the underlying MongoDB collection has changed from `{ key: 1 }` to `{ key: 1, namespace: 1 }`. This allows the same key name to exist in different namespaces without conflicts. The old index is automatically dropped and replaced on first connection, so no manual migration is needed.
491
+
492
+ #### Options Type is Now Strongly Typed
493
+
494
+ The constructor options no longer accept arbitrary keys via `[key: string]: unknown`. Options are now strictly typed with explicit properties. Any additional MongoDB driver options should be valid `MongoClientOptions` properties.
495
+
496
+ ```js
497
+ // v3 - Accepted any properties
498
+ const store = new KeyvMongo({ url: 'mongodb://...', customProp: true }); // no type error
499
+
500
+ // v6 - Strictly typed
501
+ const store = new KeyvMongo({ url: 'mongodb://...', collection: 'cache' }); // only known props + MongoClientOptions
502
+ ```
503
+
504
+ ### New Features
505
+
506
+ #### `createKeyv` Helper Function
507
+
508
+ A new `createKeyv` helper simplifies creating a Keyv instance with the MongoDB adapter.
509
+
510
+ ```js
511
+ import { createKeyv } from '@keyv/mongo';
512
+
513
+ // Before
514
+ const store = new KeyvMongo('mongodb://localhost:27017');
515
+ const keyv = new Keyv({ store, namespace: 'my-ns' });
516
+
517
+ // After
518
+ const keyv = createKeyv({ url: 'mongodb://localhost:27017', namespace: 'my-ns' });
519
+ ```
520
+
521
+ #### `setMany` Method
522
+
523
+ Batch set multiple key-value pairs in a single operation using MongoDB `bulkWrite`.
524
+
525
+ ```js
526
+ await store.setMany([
527
+ { key: 'key1', value: 'value1' },
528
+ { key: 'key2', value: 'value2', ttl: 5000 },
529
+ ]);
530
+ ```
531
+
532
+ #### `hasMany` Method
533
+
534
+ Check if multiple keys exist in a single query using the `$in` operator.
535
+
536
+ ```js
537
+ const results = await store.hasMany(['key1', 'key2', 'key3']);
538
+ // [true, true, false]
539
+ ```
540
+
541
+ #### `clearExpired` Method
542
+
543
+ Manually remove expired files from GridFS storage.
544
+
545
+ ```js
546
+ const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
547
+ await store.clearExpired();
548
+ ```
549
+
550
+ #### `clearUnusedFor` Method
551
+
552
+ Remove GridFS files that have not been accessed for a specified duration.
553
+
554
+ ```js
555
+ const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
556
+ await store.clearUnusedFor(3600); // remove files unused for 1 hour
557
+ ```
558
+
38
559
  ## License
39
560
 
40
561
  [MIT © Jared Wray](LISCENCE)