@mastra/mongodb 0.0.0-vnext-inngest-20250508122351 → 0.0.0-vnextAgentNetwork-20250527091247
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/CHANGELOG.md +172 -2
- package/README.md +50 -0
- package/dist/_tsup-dts-rollup.d.cts +153 -24
- package/dist/_tsup-dts-rollup.d.ts +153 -24
- package/dist/index.cjs +596 -31
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +596 -32
- package/docker-compose.yaml +30 -0
- package/package.json +8 -5
- package/src/index.ts +1 -0
- package/src/storage/index.test.ts +778 -0
- package/src/storage/index.ts +675 -0
- package/src/vector/index.test.ts +26 -13
- package/src/vector/index.ts +89 -48
- package/docker-compose.yml +0 -8
package/src/vector/index.test.ts
CHANGED
|
@@ -60,7 +60,7 @@ async function createIndexAndWait(
|
|
|
60
60
|
metric: 'cosine' | 'euclidean' | 'dotproduct',
|
|
61
61
|
) {
|
|
62
62
|
await vectorDB.createIndex({ indexName, dimension, metric });
|
|
63
|
-
await vectorDB.waitForIndexReady(indexName);
|
|
63
|
+
await vectorDB.waitForIndexReady({ indexName });
|
|
64
64
|
const created = await waitForCondition(
|
|
65
65
|
async () => {
|
|
66
66
|
const cols = await vectorDB.listIndexes();
|
|
@@ -75,7 +75,7 @@ async function createIndexAndWait(
|
|
|
75
75
|
// Delete index (collection) and wait until it is removed
|
|
76
76
|
async function deleteIndexAndWait(vectorDB: MongoDBVector, indexName: string) {
|
|
77
77
|
try {
|
|
78
|
-
await vectorDB.deleteIndex(indexName);
|
|
78
|
+
await vectorDB.deleteIndex({ indexName });
|
|
79
79
|
const deleted = await waitForCondition(
|
|
80
80
|
async () => {
|
|
81
81
|
const cols = await vectorDB.listIndexes();
|
|
@@ -105,7 +105,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
105
105
|
// Cleanup any existing collections
|
|
106
106
|
try {
|
|
107
107
|
const cols = await vectorDB.listIndexes();
|
|
108
|
-
await Promise.all(cols.map(c => vectorDB.deleteIndex(c)));
|
|
108
|
+
await Promise.all(cols.map(c => vectorDB.deleteIndex({ indexName: c })));
|
|
109
109
|
const deleted = await waitForCondition(async () => (await vectorDB.listIndexes()).length === 0, 30000, 2000);
|
|
110
110
|
if (!deleted) throw new Error('Timed out waiting for collections to be deleted');
|
|
111
111
|
} catch (error) {
|
|
@@ -119,12 +119,12 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
119
119
|
|
|
120
120
|
afterAll(async () => {
|
|
121
121
|
try {
|
|
122
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
122
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
123
123
|
} catch (error) {
|
|
124
124
|
console.error('Failed to delete test collection:', error);
|
|
125
125
|
}
|
|
126
126
|
try {
|
|
127
|
-
await vectorDB.deleteIndex(testIndexName2);
|
|
127
|
+
await vectorDB.deleteIndex({ indexName: testIndexName2 });
|
|
128
128
|
} catch (error) {
|
|
129
129
|
console.error('Failed to delete test collection:', error);
|
|
130
130
|
}
|
|
@@ -137,7 +137,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
137
137
|
expect(cols).toContain(testIndexName);
|
|
138
138
|
|
|
139
139
|
// Check stats (should be zero docs initially)
|
|
140
|
-
const initialStats = await vectorDB.describeIndex(testIndexName);
|
|
140
|
+
const initialStats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
141
141
|
expect(initialStats).toEqual({ dimension: 4, metric: 'cosine', count: 0 });
|
|
142
142
|
|
|
143
143
|
// Upsert 4 vectors with metadata
|
|
@@ -153,7 +153,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
153
153
|
|
|
154
154
|
// Wait for the document count to update (increased delay to 5000ms)
|
|
155
155
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
156
|
-
const updatedStats = await vectorDB.describeIndex(testIndexName);
|
|
156
|
+
const updatedStats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
157
157
|
expect(updatedStats.count).toEqual(4);
|
|
158
158
|
|
|
159
159
|
// Query for similar vectors (delay again to allow for index update)
|
|
@@ -175,7 +175,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
175
175
|
expect(filteredResults[0]?.metadata).toEqual({ label: 'vector2' });
|
|
176
176
|
|
|
177
177
|
// Final stats should show > 0 documents
|
|
178
|
-
const finalStats = await vectorDB.describeIndex(testIndexName);
|
|
178
|
+
const finalStats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
179
179
|
expect(finalStats.count).toBeGreaterThan(0);
|
|
180
180
|
});
|
|
181
181
|
|
|
@@ -379,7 +379,11 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
379
379
|
const idToBeUpdated = ids[0];
|
|
380
380
|
const newVector = [1, 2, 3, 4];
|
|
381
381
|
const newMetaData = { test: 'updates' };
|
|
382
|
-
await vectorDB.
|
|
382
|
+
await vectorDB.updateVector({
|
|
383
|
+
indexName,
|
|
384
|
+
id: idToBeUpdated,
|
|
385
|
+
update: { vector: newVector, metadata: newMetaData },
|
|
386
|
+
});
|
|
383
387
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
384
388
|
const results = await vectorDB.query({
|
|
385
389
|
indexName,
|
|
@@ -399,7 +403,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
399
403
|
expect(ids).toHaveLength(4);
|
|
400
404
|
const idToBeUpdated = ids[0];
|
|
401
405
|
const newMetaData = { test: 'metadata only update' };
|
|
402
|
-
await vectorDB.
|
|
406
|
+
await vectorDB.updateVector({ indexName, id: idToBeUpdated, update: { metadata: newMetaData } });
|
|
403
407
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
404
408
|
const results = await vectorDB.query({
|
|
405
409
|
indexName,
|
|
@@ -419,7 +423,7 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
419
423
|
expect(ids).toHaveLength(4);
|
|
420
424
|
const idToBeUpdated = ids[0];
|
|
421
425
|
const newVector = [1, 2, 3, 4];
|
|
422
|
-
await vectorDB.
|
|
426
|
+
await vectorDB.updateVector({ indexName, id: idToBeUpdated, update: { vector: newVector } });
|
|
423
427
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
424
428
|
const results = await vectorDB.query({
|
|
425
429
|
indexName,
|
|
@@ -434,15 +438,24 @@ describe('MongoDBVector Integration Tests', () => {
|
|
|
434
438
|
expect(updatedResult?.vector).toEqual(newVector);
|
|
435
439
|
});
|
|
436
440
|
it('should throw exception when no updates are given', async () => {
|
|
437
|
-
await expect(vectorDB.
|
|
441
|
+
await expect(vectorDB.updateVector({ indexName, id: 'nonexistent-id', update: {} })).rejects.toThrow(
|
|
442
|
+
'No updates provided',
|
|
443
|
+
);
|
|
438
444
|
});
|
|
439
445
|
it('should delete the vector by id', async () => {
|
|
440
446
|
const ids = await vectorDB.upsert({ indexName, vectors: testVectors });
|
|
441
447
|
expect(ids).toHaveLength(4);
|
|
442
448
|
const idToBeDeleted = ids[0];
|
|
443
|
-
|
|
449
|
+
|
|
450
|
+
const initialStats = await vectorDB.describeIndex({ indexName });
|
|
451
|
+
|
|
452
|
+
await vectorDB.deleteVector({ indexName, id: idToBeDeleted });
|
|
444
453
|
const results = await vectorDB.query({ indexName, queryVector: [1, 0, 0, 0], topK: 2 });
|
|
445
454
|
expect(results.map(res => res.id)).not.toContain(idToBeDeleted);
|
|
455
|
+
|
|
456
|
+
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait for count to update
|
|
457
|
+
const finalStats = await vectorDB.describeIndex({ indexName });
|
|
458
|
+
expect(finalStats.count).toBe(initialStats.count - 1);
|
|
446
459
|
});
|
|
447
460
|
});
|
|
448
461
|
|
package/src/vector/index.ts
CHANGED
|
@@ -5,9 +5,10 @@ import type {
|
|
|
5
5
|
CreateIndexParams,
|
|
6
6
|
UpsertVectorParams,
|
|
7
7
|
QueryVectorParams,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
DescribeIndexParams,
|
|
9
|
+
DeleteIndexParams,
|
|
10
|
+
DeleteVectorParams,
|
|
11
|
+
UpdateVectorParams,
|
|
11
12
|
} from '@mastra/core/vector';
|
|
12
13
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
13
14
|
import { MongoClient } from 'mongodb';
|
|
@@ -17,10 +18,6 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
17
18
|
import { MongoDBFilterTranslator } from './filter';
|
|
18
19
|
|
|
19
20
|
// Define necessary types and interfaces
|
|
20
|
-
export type MongoDBUpsertArgs = [...UpsertVectorArgs, string[]?];
|
|
21
|
-
export type MongoDBQueryArgs = [...QueryVectorArgs, string?];
|
|
22
|
-
export type MongoDBUpsertParams = ParamsToArgs<MongoDBUpsertArgs>;
|
|
23
|
-
|
|
24
21
|
export interface MongoDBUpsertVectorParams extends UpsertVectorParams {
|
|
25
22
|
documents?: string[];
|
|
26
23
|
}
|
|
@@ -29,6 +26,12 @@ export interface MongoDBQueryVectorParams extends QueryVectorParams {
|
|
|
29
26
|
documentFilter?: VectorFilter;
|
|
30
27
|
}
|
|
31
28
|
|
|
29
|
+
export interface MongoDBIndexReadyParams {
|
|
30
|
+
indexName: string;
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
checkIntervalMs?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
32
35
|
// Define the document interface
|
|
33
36
|
interface MongoDBDocument extends Document {
|
|
34
37
|
_id: string; // Explicitly declare '_id' as string
|
|
@@ -68,9 +71,7 @@ export class MongoDBVector extends MastraVector {
|
|
|
68
71
|
await this.client.close();
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
async createIndex(
|
|
72
|
-
const { indexName, dimension, metric = 'cosine' } = params;
|
|
73
|
-
|
|
74
|
+
async createIndex({ indexName, dimension, metric = 'cosine' }: CreateIndexParams): Promise<void> {
|
|
74
75
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
75
76
|
throw new Error('Dimension must be a positive integer');
|
|
76
77
|
}
|
|
@@ -118,7 +119,19 @@ export class MongoDBVector extends MastraVector {
|
|
|
118
119
|
await collection.updateOne({ _id: '__index_metadata__' }, { $set: { dimension, metric } }, { upsert: true });
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Waits for the index to be ready.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} indexName - The name of the index to wait for
|
|
126
|
+
* @param {number} timeoutMs - The maximum time in milliseconds to wait for the index to be ready (default: 60000)
|
|
127
|
+
* @param {number} checkIntervalMs - The interval in milliseconds at which to check if the index is ready (default: 2000)
|
|
128
|
+
* @returns A promise that resolves when the index is ready
|
|
129
|
+
*/
|
|
130
|
+
async waitForIndexReady({
|
|
131
|
+
indexName,
|
|
132
|
+
timeoutMs = 60000,
|
|
133
|
+
checkIntervalMs = 2000,
|
|
134
|
+
}: MongoDBIndexReadyParams): Promise<void> {
|
|
122
135
|
const collection = await this.getCollection(indexName, true);
|
|
123
136
|
const indexNameInternal = `${indexName}_vector_index`;
|
|
124
137
|
|
|
@@ -135,15 +148,13 @@ export class MongoDBVector extends MastraVector {
|
|
|
135
148
|
throw new Error(`Index "${indexNameInternal}" did not become ready within timeout`);
|
|
136
149
|
}
|
|
137
150
|
|
|
138
|
-
async upsert(
|
|
139
|
-
const { indexName, vectors, metadata, ids, documents } = params;
|
|
140
|
-
|
|
151
|
+
async upsert({ indexName, vectors, metadata, ids, documents }: MongoDBUpsertVectorParams): Promise<string[]> {
|
|
141
152
|
const collection = await this.getCollection(indexName);
|
|
142
153
|
|
|
143
154
|
this.collectionForValidation = collection;
|
|
144
155
|
|
|
145
156
|
// Get index stats to check dimension
|
|
146
|
-
const stats = await this.describeIndex(indexName);
|
|
157
|
+
const stats = await this.describeIndex({ indexName });
|
|
147
158
|
|
|
148
159
|
// Validate vector dimensions
|
|
149
160
|
await this.validateVectorDimensions(vectors, stats.dimension);
|
|
@@ -187,9 +198,14 @@ export class MongoDBVector extends MastraVector {
|
|
|
187
198
|
return generatedIds;
|
|
188
199
|
}
|
|
189
200
|
|
|
190
|
-
async query(
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
async query({
|
|
202
|
+
indexName,
|
|
203
|
+
queryVector,
|
|
204
|
+
topK = 10,
|
|
205
|
+
filter,
|
|
206
|
+
includeVector = false,
|
|
207
|
+
documentFilter,
|
|
208
|
+
}: MongoDBQueryVectorParams): Promise<QueryResult[]> {
|
|
193
209
|
const collection = await this.getCollection(indexName, true);
|
|
194
210
|
const indexNameInternal = `${indexName}_vector_index`;
|
|
195
211
|
|
|
@@ -255,7 +271,13 @@ export class MongoDBVector extends MastraVector {
|
|
|
255
271
|
return collections.map(col => col.name);
|
|
256
272
|
}
|
|
257
273
|
|
|
258
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Retrieves statistics about a vector index.
|
|
276
|
+
*
|
|
277
|
+
* @param {string} indexName - The name of the index to describe
|
|
278
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
279
|
+
*/
|
|
280
|
+
async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {
|
|
259
281
|
const collection = await this.getCollection(indexName, true);
|
|
260
282
|
|
|
261
283
|
// Get the count of documents, excluding the metadata document
|
|
@@ -273,7 +295,7 @@ export class MongoDBVector extends MastraVector {
|
|
|
273
295
|
};
|
|
274
296
|
}
|
|
275
297
|
|
|
276
|
-
async deleteIndex(indexName:
|
|
298
|
+
async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {
|
|
277
299
|
const collection = await this.getCollection(indexName, false); // Do not throw error if collection doesn't exist
|
|
278
300
|
if (collection) {
|
|
279
301
|
await collection.drop();
|
|
@@ -284,45 +306,64 @@ export class MongoDBVector extends MastraVector {
|
|
|
284
306
|
}
|
|
285
307
|
}
|
|
286
308
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
309
|
+
/**
|
|
310
|
+
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
311
|
+
* @param indexName - The name of the index containing the vector.
|
|
312
|
+
* @param id - The ID of the vector to update.
|
|
313
|
+
* @param update - An object containing the vector and/or metadata to update.
|
|
314
|
+
* @param update.vector - An optional array of numbers representing the new vector.
|
|
315
|
+
* @param update.metadata - An optional record containing the new metadata.
|
|
316
|
+
* @returns A promise that resolves when the update is complete.
|
|
317
|
+
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
318
|
+
*/
|
|
319
|
+
async updateVector({ indexName, id, update }: UpdateVectorParams): Promise<void> {
|
|
320
|
+
try {
|
|
321
|
+
if (!update.vector && !update.metadata) {
|
|
322
|
+
throw new Error('No updates provided');
|
|
323
|
+
}
|
|
295
324
|
|
|
296
|
-
|
|
297
|
-
|
|
325
|
+
const collection = await this.getCollection(indexName, true);
|
|
326
|
+
const updateDoc: Record<string, any> = {};
|
|
298
327
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
328
|
+
if (update.vector) {
|
|
329
|
+
const stats = await this.describeIndex({ indexName });
|
|
330
|
+
await this.validateVectorDimensions([update.vector], stats.dimension);
|
|
331
|
+
updateDoc[this.embeddingFieldName] = update.vector;
|
|
332
|
+
}
|
|
302
333
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
334
|
+
if (update.metadata) {
|
|
335
|
+
// Normalize metadata in updates too
|
|
336
|
+
const normalizedMeta = Object.keys(update.metadata).reduce(
|
|
337
|
+
(acc, key) => {
|
|
338
|
+
acc[key] =
|
|
339
|
+
update.metadata![key] instanceof Date ? update.metadata![key].toISOString() : update.metadata![key];
|
|
340
|
+
return acc;
|
|
341
|
+
},
|
|
342
|
+
{} as Record<string, any>,
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
updateDoc[this.metadataFieldName] = normalizedMeta;
|
|
346
|
+
}
|
|
313
347
|
|
|
314
|
-
|
|
348
|
+
await collection.findOneAndUpdate({ _id: id }, { $set: updateDoc });
|
|
349
|
+
} catch (error: any) {
|
|
350
|
+
throw new Error(`Failed to update vector by id: ${id} for index name: ${indexName}: ${error.message}`);
|
|
315
351
|
}
|
|
316
|
-
|
|
317
|
-
await collection.findOneAndUpdate({ _id: id }, { $set: updateDoc });
|
|
318
352
|
}
|
|
319
353
|
|
|
320
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Deletes a vector by its ID.
|
|
356
|
+
* @param indexName - The name of the index containing the vector.
|
|
357
|
+
* @param id - The ID of the vector to delete.
|
|
358
|
+
* @returns A promise that resolves when the deletion is complete.
|
|
359
|
+
* @throws Will throw an error if the deletion operation fails.
|
|
360
|
+
*/
|
|
361
|
+
async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {
|
|
321
362
|
try {
|
|
322
363
|
const collection = await this.getCollection(indexName, true);
|
|
323
364
|
await collection.deleteOne({ _id: id });
|
|
324
365
|
} catch (error: any) {
|
|
325
|
-
throw new Error(`Failed to delete
|
|
366
|
+
throw new Error(`Failed to delete vector by id: ${id} for index name: ${indexName}: ${error.message}`);
|
|
326
367
|
}
|
|
327
368
|
}
|
|
328
369
|
|