@mastra/mongodb 1.0.0-beta.1 → 1.0.0-beta.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @mastra/mongodb
2
2
 
3
+ ## 1.0.0-beta.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Add new deleteVectors, updateVector by filter ([#10408](https://github.com/mastra-ai/mastra/pull/10408))
8
+
9
+ - Updated dependencies [[`21a15de`](https://github.com/mastra-ai/mastra/commit/21a15de369fe82aac26bb642ed7be73505475e8b), [`feb7ee4`](https://github.com/mastra-ai/mastra/commit/feb7ee4d09a75edb46c6669a3beaceec78811747), [`b0e2ea5`](https://github.com/mastra-ai/mastra/commit/b0e2ea5b52c40fae438b9e2f7baee6f0f89c5442), [`c456e01`](https://github.com/mastra-ai/mastra/commit/c456e0149e3c176afcefdbd9bb1d2c5917723725), [`ab035c2`](https://github.com/mastra-ai/mastra/commit/ab035c2ef6d8cc7bb25f06f1a38508bd9e6f126b), [`1a46a56`](https://github.com/mastra-ai/mastra/commit/1a46a566f45a3fcbadc1cf36bf86d351f264bfa3), [`3cf540b`](https://github.com/mastra-ai/mastra/commit/3cf540b9fbfea8f4fc8d3a2319a4e6c0b0cbfd52), [`1c6ce51`](https://github.com/mastra-ai/mastra/commit/1c6ce51f875915ab57fd36873623013699a2a65d), [`898a972`](https://github.com/mastra-ai/mastra/commit/898a9727d286c2510d6b702dfd367e6aaf5c6b0f), [`a97003a`](https://github.com/mastra-ai/mastra/commit/a97003aa1cf2f4022a41912324a1e77263b326b8), [`ccc141e`](https://github.com/mastra-ai/mastra/commit/ccc141ed27da0abc3a3fc28e9e5128152e8e37f4), [`fe3b897`](https://github.com/mastra-ai/mastra/commit/fe3b897c2ccbcd2b10e81b099438c7337feddf89), [`00123ba`](https://github.com/mastra-ai/mastra/commit/00123ba96dc9e5cd0b110420ebdba56d8f237b25), [`29c4309`](https://github.com/mastra-ai/mastra/commit/29c4309f818b24304c041bcb4a8f19b5f13f6b62), [`16785ce`](https://github.com/mastra-ai/mastra/commit/16785ced928f6f22638f4488cf8a125d99211799), [`de8239b`](https://github.com/mastra-ai/mastra/commit/de8239bdcb1d8c0cfa06da21f1569912a66bbc8a), [`b5e6cd7`](https://github.com/mastra-ai/mastra/commit/b5e6cd77fc8c8e64e0494c1d06cee3d84e795d1e), [`3759cb0`](https://github.com/mastra-ai/mastra/commit/3759cb064935b5f74c65ac2f52a1145f7352899d), [`651e772`](https://github.com/mastra-ai/mastra/commit/651e772eb1475fb13e126d3fcc01751297a88214), [`b61b93f`](https://github.com/mastra-ai/mastra/commit/b61b93f9e058b11dd2eec169853175d31dbdd567), [`bae33d9`](https://github.com/mastra-ai/mastra/commit/bae33d91a63fbb64d1e80519e1fc1acaed1e9013), [`c0b731f`](https://github.com/mastra-ai/mastra/commit/c0b731fb27d712dc8582e846df5c0332a6a0c5ba), [`43ca8f2`](https://github.com/mastra-ai/mastra/commit/43ca8f2c7334851cc7b4d3d2f037d8784bfbdd5f), [`2ca67cc`](https://github.com/mastra-ai/mastra/commit/2ca67cc3bb1f6a617353fdcab197d9efebe60d6f), [`9e67002`](https://github.com/mastra-ai/mastra/commit/9e67002b52c9be19936c420a489dbee9c5fd6a78), [`35edc49`](https://github.com/mastra-ai/mastra/commit/35edc49ac0556db609189641d6341e76771b81fc)]:
10
+ - @mastra/core@1.0.0-beta.5
11
+
3
12
  ## 1.0.0-beta.1
4
13
 
5
14
  ### Patch Changes
package/README.md CHANGED
@@ -161,10 +161,11 @@ The following distance metrics are supported:
161
161
 
162
162
  > **Note:** `documentFilter` allows filtering results based on the content of the `document` field. Example: `{ $contains: 'specific text' }` will return only vectors whose associated document contains the specified text.
163
163
 
164
+ - `updateVector({ indexName, id?, filter?, update })`: Update a single vector by ID or metadata filter
165
+ - `deleteVector({ indexName, id })`: Delete a single vector by ID
166
+ - `deleteVectors({ indexName, ids?, filter? })`: Delete multiple vectors by IDs or metadata filter
164
167
  - `listIndexes()`: List all vector-enabled collections
165
168
  - `describeIndex(indexName)`: Get collection statistics (dimension, count, metric)
166
- - `updateIndexById(indexName, id, { vector?, metadata? })`: Update a vector and/or its metadata by ID
167
- - `deleteIndexById(indexName, id)`: Delete a vector by ID
168
169
  - `deleteIndex(indexName)`: Delete a collection
169
170
  - `disconnect()`: Close the MongoDB connection
170
171
 
package/dist/index.cjs CHANGED
@@ -13,7 +13,7 @@ var evals = require('@mastra/core/evals');
13
13
 
14
14
  // package.json
15
15
  var package_default = {
16
- version: "1.0.0-beta.1"};
16
+ version: "1.0.0-beta.2"};
17
17
  var MongoDBFilterTranslator = class extends filter.BaseFilterTranslator {
18
18
  getSupportedOperators() {
19
19
  return {
@@ -355,12 +355,17 @@ var MongoDBVector = class extends vector.MastraVector {
355
355
  limit: topK
356
356
  };
357
357
  if (Object.keys(combinedFilter).length > 0) {
358
- const candidateIds = await collection.aggregate([{ $match: combinedFilter }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
358
+ const filterWithExclusion = {
359
+ $and: [{ _id: { $ne: "__index_metadata__" } }, combinedFilter]
360
+ };
361
+ const candidateIds = await collection.aggregate([{ $match: filterWithExclusion }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
359
362
  if (candidateIds.length > 0) {
360
363
  vectorSearch.filter = { _id: { $in: candidateIds } };
361
364
  } else {
362
365
  return [];
363
366
  }
367
+ } else {
368
+ vectorSearch.filter = { _id: { $ne: "__index_metadata__" } };
364
369
  }
365
370
  const pipeline = [
366
371
  {
@@ -481,7 +486,26 @@ var MongoDBVector = class extends vector.MastraVector {
481
486
  * @returns A promise that resolves when the update is complete.
482
487
  * @throws Will throw an error if no updates are provided or if the update operation fails.
483
488
  */
484
- async updateVector({ indexName, id, update }) {
489
+ async updateVector(params) {
490
+ const { indexName, update } = params;
491
+ if ("id" in params && params.id && "filter" in params && params.filter) {
492
+ throw new error.MastraError({
493
+ id: "STORAGE_MONGODB_VECTOR_UPDATE_MUTUALLY_EXCLUSIVE_PARAMS",
494
+ domain: error.ErrorDomain.STORAGE,
495
+ category: error.ErrorCategory.USER,
496
+ details: { indexName },
497
+ text: "id and filter are mutually exclusive - provide only one"
498
+ });
499
+ }
500
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
501
+ throw new error.MastraError({
502
+ id: "STORAGE_MONGODB_VECTOR_UPDATE_MISSING_PARAMS",
503
+ domain: error.ErrorDomain.STORAGE,
504
+ category: error.ErrorCategory.USER,
505
+ text: "Either id or filter must be provided",
506
+ details: { indexName }
507
+ });
508
+ }
485
509
  try {
486
510
  if (!update.vector && !update.metadata) {
487
511
  throw new Error("No updates provided");
@@ -503,17 +527,49 @@ var MongoDBVector = class extends vector.MastraVector {
503
527
  );
504
528
  updateDoc[this.metadataFieldName] = normalizedMeta;
505
529
  }
506
- await collection.findOneAndUpdate({ _id: id }, { $set: updateDoc });
530
+ if ("id" in params && params.id) {
531
+ await collection.findOneAndUpdate({ _id: params.id }, { $set: updateDoc });
532
+ } else if ("filter" in params && params.filter) {
533
+ const filter = params.filter;
534
+ if (!filter || Object.keys(filter).length === 0) {
535
+ throw new error.MastraError({
536
+ id: "STORAGE_MONGODB_VECTOR_UPDATE_EMPTY_FILTER",
537
+ domain: error.ErrorDomain.STORAGE,
538
+ category: error.ErrorCategory.USER,
539
+ details: { indexName },
540
+ text: "Cannot update with empty filter"
541
+ });
542
+ }
543
+ const mongoFilter = this.transformFilter(filter);
544
+ const transformedFilter = this.transformMetadataFilter(mongoFilter);
545
+ if (!transformedFilter || Object.keys(transformedFilter).length === 0) {
546
+ throw new error.MastraError({
547
+ id: "STORAGE_MONGODB_VECTOR_UPDATE_INVALID_FILTER",
548
+ domain: error.ErrorDomain.STORAGE,
549
+ category: error.ErrorCategory.USER,
550
+ details: { indexName },
551
+ text: "Filter produced empty query"
552
+ });
553
+ }
554
+ await collection.updateMany(transformedFilter, { $set: updateDoc });
555
+ }
507
556
  } catch (error$1) {
557
+ if (error$1 instanceof error.MastraError) {
558
+ throw error$1;
559
+ }
560
+ const errorDetails = { indexName };
561
+ if ("id" in params && params.id) {
562
+ errorDetails.id = params.id;
563
+ }
564
+ if ("filter" in params && params.filter) {
565
+ errorDetails.filter = JSON.stringify(params.filter);
566
+ }
508
567
  throw new error.MastraError(
509
568
  {
510
569
  id: "STORAGE_MONGODB_VECTOR_UPDATE_VECTOR_FAILED",
511
570
  domain: error.ErrorDomain.STORAGE,
512
571
  category: error.ErrorCategory.THIRD_PARTY,
513
- details: {
514
- indexName,
515
- id
516
- }
572
+ details: errorDetails
517
573
  },
518
574
  error$1
519
575
  );
@@ -545,6 +601,83 @@ var MongoDBVector = class extends vector.MastraVector {
545
601
  );
546
602
  }
547
603
  }
604
+ async deleteVectors({ indexName, filter, ids }) {
605
+ if (!filter && !ids) {
606
+ throw new error.MastraError({
607
+ id: "STORAGE_MONGODB_VECTOR_DELETE_MISSING_PARAMS",
608
+ domain: error.ErrorDomain.STORAGE,
609
+ category: error.ErrorCategory.USER,
610
+ details: { indexName },
611
+ text: "Either filter or ids must be provided"
612
+ });
613
+ }
614
+ if (filter && ids) {
615
+ throw new error.MastraError({
616
+ id: "STORAGE_MONGODB_VECTOR_DELETE_CONFLICTING_PARAMS",
617
+ domain: error.ErrorDomain.STORAGE,
618
+ category: error.ErrorCategory.USER,
619
+ details: { indexName },
620
+ text: "Cannot provide both filter and ids - they are mutually exclusive"
621
+ });
622
+ }
623
+ try {
624
+ const collection = await this.getCollection(indexName, true);
625
+ if (ids) {
626
+ if (ids.length === 0) {
627
+ throw new error.MastraError({
628
+ id: "STORAGE_MONGODB_VECTOR_DELETE_EMPTY_IDS",
629
+ domain: error.ErrorDomain.STORAGE,
630
+ category: error.ErrorCategory.USER,
631
+ details: { indexName },
632
+ text: "Cannot delete with empty ids array"
633
+ });
634
+ }
635
+ await collection.deleteMany({ _id: { $in: ids } });
636
+ } else {
637
+ if (!filter || Object.keys(filter).length === 0) {
638
+ throw new error.MastraError({
639
+ id: "STORAGE_MONGODB_VECTOR_DELETE_EMPTY_FILTER",
640
+ domain: error.ErrorDomain.STORAGE,
641
+ category: error.ErrorCategory.USER,
642
+ details: { indexName },
643
+ text: "Cannot delete with empty filter"
644
+ });
645
+ }
646
+ const mongoFilter = this.transformFilter(filter);
647
+ const transformedFilter = this.transformMetadataFilter(mongoFilter);
648
+ if (!transformedFilter || Object.keys(transformedFilter).length === 0) {
649
+ throw new error.MastraError({
650
+ id: "STORAGE_MONGODB_VECTOR_DELETE_INVALID_FILTER",
651
+ domain: error.ErrorDomain.STORAGE,
652
+ category: error.ErrorCategory.USER,
653
+ details: { indexName },
654
+ text: "Filter produced empty query"
655
+ });
656
+ }
657
+ const finalFilter = {
658
+ $and: [{ _id: { $ne: "__index_metadata__" } }, transformedFilter]
659
+ };
660
+ await collection.deleteMany(finalFilter);
661
+ }
662
+ } catch (error$1) {
663
+ if (error$1 instanceof error.MastraError) {
664
+ throw error$1;
665
+ }
666
+ throw new error.MastraError(
667
+ {
668
+ id: "STORAGE_MONGODB_VECTOR_DELETE_VECTORS_FAILED",
669
+ domain: error.ErrorDomain.STORAGE,
670
+ category: error.ErrorCategory.THIRD_PARTY,
671
+ details: {
672
+ indexName,
673
+ ...filter && { filter: JSON.stringify(filter) },
674
+ ...ids && { idsCount: ids.length }
675
+ }
676
+ },
677
+ error$1
678
+ );
679
+ }
680
+ }
548
681
  // Private methods
549
682
  async getCollection(indexName, throwIfNotExists = true) {
550
683
  if (this.collections.has(indexName)) {
@@ -592,16 +725,26 @@ var MongoDBVector = class extends vector.MastraVector {
592
725
  */
593
726
  transformMetadataFilter(filter) {
594
727
  if (!filter || typeof filter !== "object") return filter;
728
+ if (Array.isArray(filter)) {
729
+ return filter.map((item) => this.transformMetadataFilter(item));
730
+ }
595
731
  const transformed = {};
596
732
  for (const [key, value] of Object.entries(filter)) {
597
733
  if (key.startsWith("$")) {
598
734
  if (Array.isArray(value)) {
599
735
  transformed[key] = value.map((item) => this.transformMetadataFilter(item));
600
- } else {
736
+ } else if (typeof value === "object" && value !== null) {
601
737
  transformed[key] = this.transformMetadataFilter(value);
738
+ } else {
739
+ transformed[key] = value;
602
740
  }
603
741
  } else if (key.startsWith("metadata.")) {
604
- transformed[key] = value;
742
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
743
+ const hasOperator = Object.keys(value).some((k) => k.startsWith("$"));
744
+ transformed[key] = hasOperator ? value : value;
745
+ } else {
746
+ transformed[key] = value;
747
+ }
605
748
  } else if (this.isMetadataField(key)) {
606
749
  transformed[`metadata.${key}`] = value;
607
750
  } else {