Stockage vectoriel MongoDB
La classe MongoDBVector fournit une recherche vectorielle au moyen de MongoDB Atlas Vector Search. Elle permet d’effectuer efficacement des recherches par similarité et de filtrer les métadonnées au sein de vos collections MongoDB.
InstallationLien direct vers Installation
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/mongodb@latest
pnpm add @mastra/mongodb@latest
yarn add @mastra/mongodb@latest
bun add @mastra/mongodb@latest
Exemple d’utilisationLien direct vers Exemple d’utilisation
import { MongoDBVector } from '@mastra/mongodb'
const store = new MongoDBVector({
id: 'mongodb-vector',
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
})
Chemin personnalisé du champ d’EmbeddingLien direct vers Chemin personnalisé du champ d’Embedding
Si vous devez stocker des Embeddings dans une structure de champs imbriqués, par exemple pour les intégrer à des collections MongoDB existantes, utilisez l’option embeddingFieldPath :
import { MongoDBVector } from '@mastra/mongodb'
const store = new MongoDBVector({
id: 'mongodb-vector',
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
embeddingFieldPath: 'text.contentEmbedding', // Store embeddings at text.contentEmbedding
})
Options du constructeurLien direct vers Options du constructeur
id:
uri:
dbName:
options?:
embeddingFieldPath?:
MéthodesLien direct vers Méthodes
connect()Lien direct vers connect
Établit la connexion au serveur MongoDB. Cette méthode est appelée automatiquement à la première utilisation, mais peut être appelée explicitement si nécessaire.
await store.connect()
createIndex()Lien direct vers createindex
Crée un nouvel index vectoriel (collection) dans MongoDB.
indexName:
dimension:
metric?:
filterFields?:
metadata.<field>). Les requêtes qui filtrent uniquement sur des champs déclarés sont transmises directement à $vectorSearch au lieu de préfiltrer les _id candidats, ce qui évite la limite BSON de 16 Mo pour les grands ensembles de résultats. Les filtres qui font référence à un champ non déclaré ou utilisent un opérateur non pris en charge par $vectorSearch reviennent automatiquement au préfiltrage.collectionName?:
indexName.searchIndexName?:
${indexName}_vector_index.allowWrites?:
upsert, updateVector, deleteVector, deleteVectors) dans une collection existante (BYO). Par défaut, un index BYO est en lecture seule : le stockage ne modifie ni ne supprime jamais les documents opérationnels appartenant à l’appelant. Cette option est ignorée pour les collections gérées, qui sont toujours accessibles en écriture. La politique est persistée avec l’enregistrement de l’index et survit aux redémarrages.waitForIndexReady()Lien direct vers waitforindexready
Attend qu’un index soit prêt après sa création. Cette méthode est utile lorsque vous devez vous assurer qu’un index est prêt avant d’effectuer des opérations.
indexName:
timeoutMs?:
checkIntervalMs?:
upsert()Lien direct vers upsert
Ajoute ou met à jour des vecteurs et leurs métadonnées dans la collection. Pour un index existant (BYO), cette opération exige allowWrites: true lors de l’appel à createIndex(), car les collections BYO sont en lecture seule par défaut.
indexName:
vectors:
metadata?:
ids?:
documents?:
query()Lien direct vers query
Recherche des vecteurs similaires avec un filtrage facultatif des métadonnées.
indexName:
queryVector:
topK?:
filter?:
metadata)documentFilter?:
includeVector?:
numCandidates?:
metadataMode?:
'field' (valeur par défaut) projette les champs gérés metadata/document, et les champs de filter sont comparés au sous-document metadata. 'document' renvoie le document source complet comme metadata — utilisez ce mode pour les collections opérationnelles existantes dont les documents possèdent leur propre structure — et les champs de filter sont comparés au document **racine** (sans préfixe metadata.). Par défaut, le champ d’Embedding est omis de metadata afin d’éviter d’alourdir la charge utile ; définissez includeVector: true pour le conserver dans metadata et l’exposer également comme vector de premier niveau.createSearchIndex()Lien direct vers createsearchindex
Provisionne un index Atlas Search (BM25/plein texte) dans la collection sous-jacente à un index et l’enregistre comme index de recherche textuelle ciblé par textQuery() et hybridQuery().
Collections gérées ou existantes (BYO) :
- Pour un index géré (créé sans
collectionName),createIndex()provisionne déjà un index plein texte dynamique nommé${collectionName}_search_indexqui couvre tous les champs de type chaîne.createSearchIndex()n’est donc nécessaire que pour obtenir un mappage limité à certains champs ou un nom d’index personnalisé. - Pour un index existant (BYO) (créé avec
collectionName),createIndex()ne crée automatiquement aucun index plein texte. L’activation detextQuery()/hybridQuery()sur une collection opérationnelle appartenant à l’appelant doit être explicite. Appelez explicitementcreateSearchIndex()pour provisionner l’index textuel (facturable). Tant que vous ne le faites pas,textQuery()/hybridQuery()lèvent une erreur explicite au lieu d’interroger un index inexistant.
Nommage :
- Lorsque
fieldsest fourni sanssearchIndexNameexplicite, l’index mappé aux champs est créé sous un nom par défaut distinct (${collectionName}_${indexName}_search_fields_index, unique pour chaque index logique), afin qu’il n’entre pas en conflit avec l’index dynamique créé automatiquement pour une collection gérée et ne soit pas ignoré silencieusement. Cet index distinct est persisté comme index de recherche textuelle ;textQuery()/hybridQuery()utilisent donc automatiquement le mappage restreint. - Lorsque
searchIndexNameest fourni, ce nom exact est utilisé et persisté.textQuery()/hybridQuery()résolvent automatiquement le nom persisté. Vous pouvez également remplacer le nom à chaque appel au moyen de leurs paramètressearchIndexName/textSearchIndexName.
indexName:
fields?:
searchIndexName?:
fields est fourni et que cette valeur est omise, un nom par défaut distinct et propre à chaque index logique est utilisé. Le mappage des champs n’est ainsi pas masqué par l’index dynamique créé automatiquement, et deux index logiques d’une même collection n’entrent pas en conflit.waitUntilReady?:
waitForSearchIndexReady() si vous préférez effectuer l’attente séparément.await store.createSearchIndex({
indexName: 'precedents',
fields: ['note', 'description'],
})
Le nom de l’index mappé aux champs inclut l’indexName logique ; deux index logiques d’une même collection obtiennent donc des index textuels distincts. Recréer le même index logique avec des fields différents exige toujours de supprimer d’abord l’index existant (IndexAlreadyExists).
waitForSearchIndexReady()Lien direct vers waitforsearchindexready
Attend que l’index de recherche plein texte (BM25) d’un index passe à l’état READY. waitForIndexReady() interroge uniquement l’index vectorSearch ; createSearchIndex() renvoie son résultat alors que l’index plein texte Atlas Search est encore en cours de création. Un appel immédiat à textQuery()/hybridQuery() peut donc échouer de façon intermittente. Appelez cette méthode (ou transmettez waitUntilReady: true à createSearchIndex()) pour bloquer jusqu’à ce que l’index textuel résolu signale l’état READY.
indexName:
searchIndexName?:
timeoutMs?:
checkIntervalMs?:
await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] })
await store.waitForSearchIndexReady({ indexName: 'precedents' })
textQuery()Lien direct vers textquery
Exécute une recherche plein texte (BM25) sur un index Atlas Search. Par défaut, elle cible l’index de recherche textuelle enregistré pour cet index (défini par createSearchIndex(), ou l’index dynamique ${collectionName}_search_index créé automatiquement par createIndex()). Transmettez searchIndexName pour cibler un index précis lors de cet appel.
Ici, les filtres de métadonnées, comme avec hybridQuery(), sont appliqués au moyen d’une étape $match. Pour la branche vectorielle de hybridQuery(), les filtres portant sur des champs non déclarés avec filterFields lors de la création de l’index sont matérialisés de manière transparente sous forme d’_id candidats (le même mécanisme de repli que celui utilisé par query()) ; les filtres sur des champs non déclarés ne provoquent donc pas d’erreur.
indexName:
query:
paths:
topK?:
filter?:
metadata)metadataMode?:
'field' (valeur par défaut) projette les champs gérés metadata/document. 'document' renvoie le document source complet comme metadata.searchIndexName?:
createSearchIndex() / createIndex().const results = await store.textQuery({
indexName: 'precedents',
query: 'shell company offshore',
paths: ['note'],
topK: 10,
})
hybridQuery()Lien direct vers hybridquery
Exécute une recherche hybride qui fusionne les résultats de similarité vectorielle et de recherche plein texte au moyen de l’opérateur $rankFusion côté serveur de MongoDB. Elle nécessite MongoDB >= 8.0 et est généralement disponible à partir de la version 8.1. Sous la version 8.0.x, son activation peut nécessiter une demande auprès du support MongoDB ; elle fonctionne dans les environnements où elle est activée, comme Atlas 8.0.x. Un index de recherche plein texte doit exister : il est créé automatiquement pour les index gérés, mais vous devez d’abord appeler explicitement createSearchIndex() pour une collection existante.
indexName:
queryVector:
query:
paths:
topK?:
filter?:
weights?:
numCandidates?:
metadataMode?:
'field' (valeur par défaut) projette les champs gérés metadata/document. 'document' renvoie le document source complet comme metadata.textSearchIndexName?:
createSearchIndex() / createIndex().const results = await store.hybridQuery({
indexName: 'precedents',
queryVector: embedding,
query: 'shell company offshore',
paths: ['note'],
topK: 10,
weights: { vector: 1, text: 1.5 }, // Favor text matches
})
hybridQuery() nécessite MongoDB >= 8.0 pour l’étape $rankFusion. Celle-ci est généralement disponible à partir de la version 8.1. Sous la version 8.0.x, son activation peut nécessiter une demande auprès du support MongoDB ; elle fonctionne dans les environnements où elle est activée, comme Atlas 8.0.x. Si vous utilisez une version antérieure ou si $rankFusion n’est pas activé dans votre déploiement 8.0.x, utilisez séparément query() et textQuery(), puis fusionnez les résultats côté client.
describeIndex()Lien direct vers describeindex
Renvoie des informations sur l’index (collection).
indexName:
Renvoie :
interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}
deleteIndex()Lien direct vers deleteindex
Supprime un index vectoriel. Le comportement dépend de la manière dont l’index a été créé :
- Index géré (créé sans
collectionName) : supprime toute la collection et l’ensemble de ses données. - Index existant (BYO) (créé avec
collectionName) : supprime l’index Atlas vectorSearch et, si un index a été provisionné aveccreateSearchIndex(), l’index de recherche plein texte associé. La collection opérationnelle de l’appelant et ses documents sont conservés. Ce stockage ne supprime jamais une collection qu’il n’a pas créée.
La classification BYO est enregistrée durablement lors de la création de l’index ; elle est donc appliquée correctement, même par un autre processus, par exemple lorsqu’un index est créé par une tâche de configuration puis supprimé ultérieurement par un service de longue durée. Transmettez toujours le nom logique de l’index (l’indexName utilisé avec createIndex), et non le nom physique de la collection.
indexName:
listIndexes()Lien direct vers listindexes
Répertorie les noms d’index Mastra logiques (les valeurs indexName transmises à createIndex), et non les noms physiques des collections. Pour un index existant dont les données résident dans une collection opérationnelle, le nom logique de l’index est renvoyé à la place du nom physique de la collection. Cette valeur peut être retransmise directement à deleteIndex() / describeIndex(). Les index gérés créés avant l’introduction des métadonnées durables sont toujours découverts au moyen de leur index de recherche ${name}_vector_index. La collection du registre interne n’est jamais répertoriée.
Renvoie : Promise<string[]>
updateVector()Lien direct vers updatevector
Met à jour un seul vecteur à partir de son ID ou d’un filtre de métadonnées. Vous devez fournir id ou filter, mais pas les deux.
Les collections existantes sont en lecture seule par défaut.
upsert(),updateVector(),deleteVector()etdeleteVectors()lèvent une erreur de catégorie USER sur un index BYO, sauf s’il a été créé avecallowWrites: true. Consultez la section Indexer une collection existante.
indexName:
id?:
filter?:
update:
update.vector?:
update.metadata?:
deleteVector()Lien direct vers deletevector
Supprime d’un index une entrée vectorielle précise à partir de son ID.
indexName:
id:
deleteVectors()Lien direct vers deletevectors
Supprime plusieurs vecteurs à partir de leurs ID ou d’un filtre de métadonnées. Vous devez fournir ids ou filter, mais pas les deux.
indexName:
ids?:
filter?:
disconnect()Lien direct vers disconnect
Ferme la connexion du client MongoDB. Cette méthode doit être appelée lorsque vous avez terminé d’utiliser le stockage.
Types de réponsesLien direct vers Types de réponses
Les résultats des requêtes sont renvoyés au format suivant :
interface QueryResult {
id: string
score: number
metadata: Record<string, any>
vector?: number[] // Only included if includeVector is true
}
Gestion des erreursLien direct vers Gestion des erreurs
Le stockage lève des erreurs typées qui peuvent être interceptées :
try {
await store.query({
indexName: 'my_collection',
queryVector: queryVector,
})
} catch (error) {
// Handle specific error cases
if (error.message.includes('Invalid collection name')) {
console.error(
'Collection name must start with a letter or underscore and contain only valid characters.',
)
} else if (error.message.includes('Collection not found')) {
console.error('The specified collection does not exist')
} else {
console.error('Vector store error:', error.message)
}
}
Indexer une collection existanteLien direct vers Indexer une collection existante
Vous pouvez créer un index vectoriel dans une collection opérationnelle existante plutôt que d’utiliser une collection gérée. Cette approche est utile lorsque vous souhaitez ajouter des fonctionnalités de recherche vectorielle à des documents déjà présents dans votre base de données MongoDB.
import { MongoDBVector } from '@mastra/mongodb'
const store = new MongoDBVector({
id: 'mongodb-vector',
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
})
// Create a vector index on an existing 'transactions' collection
await store.createIndex({
indexName: 'precedents',
dimension: 1024,
collectionName: 'transactions', // Use existing collection
searchIndexName: 'txn_vec_idx', // Custom search index name
})
// Wait for the index to be ready
await store.waitForIndexReady({ indexName: 'precedents' })
// Query using document mode to get full source documents
const hits = await store.query({
indexName: 'precedents',
queryVector: embeddings,
topK: 5,
metadataMode: 'document', // Returns full document as metadata
})
// hits[0].metadata now contains all fields from the source document
console.log(hits[0].metadata.amount, hits[0].metadata.customField)
// Full-text / hybrid search on a BYO collection is opt-in: provision the text index first.
await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] })
Remarques importantes :
- La collection doit déjà exister et contenir des documents avec un champ
embedding(ou l’embeddingFieldPathpersonnalisé que vous avez configuré). - La collection n’est jamais créée ni supprimée lorsque vous utilisez
collectionName. - Un index BYO est en lecture seule par défaut.
upsert(),updateVector(),deleteVector()etdeleteVectors()lèvent une erreur explicite au lieu de modifier les documents opérationnels appartenant à l’appelant. Pour permettre au stockage d’écrire des Embeddings dans votre collection, ou d’en supprimer des documents, activez explicitement cette possibilité aveccreateIndex({ ..., allowWrites: true }). La politique est persistée et survit aux redémarrages. Les entrées écrites par d’anciennes versions sans ce flag sont traitées en lecture seule (échec sécurisé). - Utilisez
metadataMode: 'document'lors des requêtes afin de récupérer le document source complet commemetadata. - En mode
'document', l’Embedding est omis demetadatapar défaut ; transmettezincludeVector: truepour le conserver et l’exposer également commevectorde premier niveau. - En mode
'document', le filtrage s’effectue sur les champs du document racine, et non sur un sous-documentmetadata.imbriqué.filter: { lane: 'fraud' }correspond au champlanede premier niveau de vos documents opérationnels (dans le mode'field'par défaut, les champs nus sont réécrits sous la formemetadata.<field>pour les collections gérées). Les chemins de transmission directe et de repli$matchrespectent tous deux ce comportement. - Les
ObjectId_idnatifs sont pris en charge. Les collections opérationnelles utilisent souvent des clésObjectId; les résultats des requêtes convertissent_iden chaîne (conformément au contratQueryResult.id), etdeleteVector()/updateVector()/deleteVectors()acceptent cette chaîne et la font correspondre au documentObjectIdsous-jacent. Les collections gérées (dont les_idsont des chaînes) ne sont pas affectées. - La recherche plein texte et la recherche hybride dans une collection BYO doivent être activées explicitement : aucun index plein texte n’est créé automatiquement. Appelez donc
createSearchIndex()avanttextQuery()/hybridQuery(). L’index plein texte est créé de façon asynchrone. AppelezwaitForSearchIndexReady()(ou transmettezwaitUntilReady: true) avant une requête textuelle ou hybride immédiate. - Sur un index BYO,
deleteIndex()supprime l’index vectoriel (ainsi que l’index textuel s’il en existe un), mais conserve la collection et ses documents.
Bonnes pratiquesLien direct vers Bonnes pratiques
- Indexez les champs de métadonnées utilisés dans les filtres afin d’optimiser les performances des requêtes.
- Adoptez une convention de nommage cohérente pour les champs de métadonnées afin d’éviter des résultats inattendus.
- Surveillez régulièrement les statistiques des index et des collections pour garantir l’efficacité des recherches.
- Lorsque vous indexez des collections existantes, assurez-vous que tous les documents possèdent le champ
embeddingrequis.
Exemple d’utilisationLien direct vers Exemple d’utilisation
Embeddings vectoriels avec MongoDBLien direct vers vector-embeddings-with-mongodb
Les Embeddings sont des vecteurs numériques utilisés par le semanticRecall de la mémoire pour récupérer les messages associés en fonction de leur sens, et non de mots-clés.
MongoDB Atlas Vector Search est recommandé pour une utilisation en production. Pour les déploiements auto-hébergés, Vector Search est disponible avec les déploiements Atlas locaux au moyen de l’interface CLI Atlas.
Cette configuration utilise FastEmbed, un modèle d’Embedding local, pour générer des Embeddings vectoriels.
Pour l’utiliser, installez @mastra/fastembed :
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/fastembed@latest
pnpm add @mastra/fastembed@latest
yarn add @mastra/fastembed@latest
bun add @mastra/fastembed@latest
Ajoutez le code suivant à votre Agent :
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { MongoDBStore, MongoDBVector } from '@mastra/mongodb'
import { fastembed } from '@mastra/fastembed'
export const mongodbAgent = new Agent({
id: 'mongodb-agent',
name: 'mongodb-agent',
instructions:
'You are an AI agent with the ability to automatically recall memories from previous interactions.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new MongoDBStore({
id: 'mongodb-storage',
uri: process.env.MONGODB_URI!,
dbName: process.env.MONGODB_DB_NAME!,
}),
vector: new MongoDBVector({
id: 'mongodb-vector',
uri: process.env.MONGODB_URI!,
dbName: process.env.MONGODB_DB_NAME!,
}),
embedder: fastembed,
options: {
lastMessages: 10,
semanticRecall: {
topK: 3,
messageRange: 2,
},
generateTitle: true, // generates descriptive thread titles automatically
},
}),
})
Embeddings vectoriels avec VoyageAILien direct vers Embeddings vectoriels avec VoyageAI
VoyageAI fournit des modèles d’Embedding spécialisés et optimisés pour les tâches de récupération. VoyageAI est également intégré à MongoDB Atlas pour les Embeddings multimodaux.
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/voyageai@latest
pnpm add @mastra/voyageai@latest
yarn add @mastra/voyageai@latest
bun add @mastra/voyageai@latest
Exemple d’utilisation de base :
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { MongoDBStore, MongoDBVector } from '@mastra/mongodb'
import { voyage } from '@mastra/voyageai'
export const mongodbVoyageAgent = new Agent({
id: 'mongodb-voyage-agent',
name: 'MongoDB VoyageAI Agent',
instructions: 'You are an AI agent with semantic recall powered by VoyageAI and MongoDB.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
storage: new MongoDBStore({
id: 'mongodb-storage',
uri: process.env.MONGODB_URI!,
dbName: process.env.MONGODB_DB_NAME!,
}),
vector: new MongoDBVector({
id: 'mongodb-vector',
uri: process.env.MONGODB_URI!,
dbName: process.env.MONGODB_DB_NAME!,
}),
embedder: voyage, // VoyageAI's default model (voyage-3.5, 1024 dimensions)
options: {
lastMessages: 10,
semanticRecall: {
topK: 5,
messageRange: 2,
},
},
}),
})
Pour obtenir des exemples détaillés d’Embeddings VoyageAI, notamment avec des modèles spécialisés, des Embeddings multimodaux et l’optimisation de la récupération, consultez la documentation des Embeddings VoyageAI.