> Discover all available pages from the documentation index: https://mastra.zisheng.pro/llms.txt # MongoDB Vector 存储 `MongoDBVector` 类使用 [MongoDB Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/) 提供 Vector 搜索。它支持在 MongoDB 集合中进行高效的相似度搜索和元数据筛选。 ## 安装 **npm**: ```bash npm install @mastra/mongodb@latest ``` **pnpm**: ```bash pnpm add @mastra/mongodb@latest ``` **Yarn**: ```bash yarn add @mastra/mongodb@latest ``` **Bun**: ```bash bun add @mastra/mongodb@latest ``` ## 用法示例 ```typescript import { MongoDBVector } from '@mastra/mongodb' const store = new MongoDBVector({ id: 'mongodb-vector', uri: process.env.MONGODB_URI, dbName: process.env.MONGODB_DB_NAME, }) ``` ### 自定义嵌入字段路径 如果需要将嵌入存储在嵌套字段结构中(例如,与现有 MongoDB 集合集成),请使用 `embeddingFieldPath` 选项: ```typescript 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 }) ``` ## 构造函数选项 **id** (`string`): 此 Vector 存储实例的唯一标识符 **uri** (`string`): MongoDB 连接字符串 **dbName** (`string`): 要使用的 MongoDB 数据库名称 **options** (`MongoClientOptions`): 可选的 MongoDB 客户端选项 **embeddingFieldPath** (`string`): 存储 Vector 嵌入的字段路径。支持使用点号表示法的嵌套路径(例如 'text.contentEmbedding')。 (Default: `embedding`) ## 方法 ### `connect()` 建立与 MongoDB 服务器的连接。首次使用时会自动调用,也可在需要时显式调用。 ```typescript await store.connect() ``` ### `createIndex()` 在 MongoDB 中创建新的 Vector 索引(集合)。 **indexName** (`string`): 要创建的集合名称 **dimension** (`number`): Vector 维度(必须与嵌入模型匹配) **metric** (`'cosine' | 'euclidean' | 'dotproduct'`): 相似度搜索使用的距离度量 (Default: `cosine`) **filterFields** (`string[]`): 要在 Atlas vectorSearch 索引中声明为筛选字段的元数据字段名称(注册为 metadata.\)。仅筛选已声明字段的查询会直接下推到 $vectorSearch,而不是预先筛选候选 \_id,从而避免大型结果集的 16 MB BSON 限制。引用未声明字段或使用 $vectorSearch 不支持的运算符时,会自动回退到预筛选。 **collectionName** (`string`): 将 Vector 存储在现有(业务)集合中,而不是以索引命名的托管集合中。设置此选项后,该存储绝不会创建或删除该集合。默认值为 indexName。 **searchIndexName** (`string`): 在集合上创建的 Atlas vectorSearch 索引名称。默认值为 ${indexName}\_vector\_index。 **allowWrites** (`boolean`): 选择允许对自带集合执行写操作(upsert、updateVector、deleteVector、deleteVectors)。BYO 索引默认为只读:该存储绝不会修改或删除调用方拥有的业务文档。托管集合始终可写,因此会忽略此选项。该策略随索引注册持久化,重启后仍然有效。 (Default: `false`) ### `waitForIndexReady()` 等待索引在创建后进入就绪状态。需要在执行操作前确保索引已就绪时,此方法很有用。 **indexName** (`string`): 要等待的索引名称 **timeoutMs** (`number`): 最长等待时间,以毫秒为单位 (Default: `60000`) **checkIntervalMs** (`number`): 状态检查间隔,以毫秒为单位 (Default: `2000`) ### `upsert()` 在集合中添加或更新 Vector 及其元数据。对于自带索引,这要求将 `allowWrites: true` 传给 `createIndex()`,因为 BYO 集合默认为只读。 **indexName** (`string`): 要插入数据的集合名称 **vectors** (`number[][]`): 嵌入 Vector 数组 **metadata** (`Record[]`): 每个 Vector 的元数据 **ids** (`string[]`): 可选的 Vector ID(未提供时自动生成) **documents** (`string[]`): 可选的文档文本内容,与 Vector 一同存储 ### `query()` 搜索相似 Vector,并可选择使用元数据筛选。 **indexName** (`string`): 要搜索的集合名称 **queryVector** (`number[]`): 用于查找相似 Vector 的查询 Vector **topK** (`number`): 要返回的结果数量 (Default: `10`) **filter** (`Record`): 元数据筛选条件(应用于 metadata 字段) **documentFilter** (`Record`): 对原始文档字段进行筛选(不仅限于元数据) **includeVector** (`boolean`): 结果中是否包含 Vector 数据 (Default: `false`) **numCandidates** (`number`): HNSW 图在选择 top-K 结果前考虑的候选项数量。值越高,召回率越高,但延迟也会增加。参见:https\://www\.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/ (Default: `20 * topK (capped at 10000)`) **metadataMode** (`'field' | 'document'`): 'field'(默认值)会投影托管的 metadata/document 字段,并将 filter 字段与 metadata 子文档匹配。'document' 将完整源文档作为 metadata 返回,适用于文档结构自定义的自带业务集合;filter 字段会与\*\*根\*\*文档匹配(无 metadata. 前缀)。默认从 metadata 中省略嵌入字段(以避免负载过大);设置 includeVector: true 可在 metadata 中保留该字段,并将其作为顶层 vector 公开。 (Default: `field`) ### `createSearchIndex()` 在索引所基于的集合上配置 Atlas Search(BM25/全文)索引,并将其记录为 `textQuery()` 和 `hybridQuery()` 的目标文本搜索索引。 **托管集合与自带集合:** - 对于**托管**索引(未使用 `collectionName` 创建),`createIndex()` 已配置名为 `${collectionName}_search_index` 的\_动态\_全文索引(覆盖所有字符串字段)。因此,只有需要**字段受限**的映射或**自定义索引名称**时才需要使用 `createSearchIndex()`。 - 对于**自带**索引(使用 `collectionName` 创建),`createIndex()` 不会自动创建任何全文索引。在调用方拥有的业务集合上启用 `textQuery()`/`hybridQuery()` 需要主动选择。请显式调用 `createSearchIndex()` 来配置(收费的)文本索引。在此之前,`textQuery()`/`hybridQuery()` 会抛出明确错误,而不会查询不存在的索引。 命名: - 提供 `fields` 但**未**显式提供 `searchIndexName` 时,字段映射索引会使用一个**不同的**默认名称(`${collectionName}_${indexName}_search_fields_index`,每个逻辑索引唯一),避免与托管集合自动创建的动态索引冲突并被静默忽略。这个不同的索引会作为文本搜索索引持久化,因此 `textQuery()`/`hybridQuery()` 会自动使用受限映射。 - 提供 `searchIndexName` 时,会使用并持久化该确切名称。`textQuery()`/`hybridQuery()` 会自动解析持久化的名称。你也可以通过各自的 `searchIndexName` / `textSearchIndexName` 参数为每次调用覆盖该名称。 **indexName** (`string`): 其集合将包含搜索索引的 Mastra 索引名称 **fields** (`string[]`): 要为全文搜索建立索引的字段名称。省略时使用动态映射(所有字符串字段)。 **searchIndexName** (`string`): Atlas Search 索引的名称。提供 fields 但省略此项时,会使用每个逻辑索引唯一且互不相同的默认名称,这样字段映射就不会被自动创建的动态索引遮蔽,并且同一集合上的两个逻辑索引不会发生冲突。 (Default: ``${collectionName}_search_index(提供 `fields` 时为 ${collectionName}_${indexName}_search_fields_index)``) **waitUntilReady** (`boolean`): 为 true 时,会阻塞至已配置的全文索引报告 READY 后再完成。默认值为 false,以避免意外延迟;如果希望单独等待,请显式调用 waitForSearchIndexReady()。 (Default: `false`) ```typescript await store.createSearchIndex({ indexName: 'precedents', fields: ['note', 'description'], }) ``` 字段映射索引名称包含逻辑 `indexName`,因此同一集合上的两个逻辑索引会获得不同的文本索引。使用不同的 `fields` 重新创建\_同一个\_逻辑索引时,仍需先删除现有索引(`IndexAlreadyExists`)。 ### `waitForSearchIndexReady()` 等待索引的全文(BM25)搜索索引变为 READY。`waitForIndexReady()` 只轮询 vectorSearch 索引;Atlas Search 全文索引仍在构建时 `createSearchIndex()` 就会返回,因此立即调用 `textQuery()`/`hybridQuery()` 可能间歇性失败。调用此方法(或将 `waitUntilReady: true` 传给 `createSearchIndex()`)可阻塞至解析出的文本索引报告 READY。 **indexName** (`string`): 要等待其文本索引的逻辑索引名称 **searchIndexName** (`string`): 覆盖解析出的文本搜索索引名称 **timeoutMs** (`number`): 最长等待时间,以毫秒为单位 (Default: `60000`) **checkIntervalMs** (`number`): 状态检查间隔,以毫秒为单位 (Default: `2000`) ```typescript await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] }) await store.waitForSearchIndexReady({ indexName: 'precedents' }) ``` ### `textQuery()` 对 Atlas Search 索引运行全文(BM25)搜索。默认情况下,它以为此索引记录的文本搜索索引为目标(由 `createSearchIndex()` 设置,或动态 `${collectionName}_search_index`,后者由 `createIndex()` 自动创建)。传入 `searchIndexName` 可将此次调用指向特定索引。 此处的元数据筛选条件(与 `hybridQuery()` 一样)通过 `$match` 阶段应用。对于 `hybridQuery()` 的 Vector 分支,在创建索引时未通过 `filterFields` 声明的字段筛选条件会透明地具体化为候选 `_id`(与 `query()` 使用的回退机制相同),因此未声明字段的筛选不会报错。 **indexName** (`string`): 要搜索的 Mastra 索引名称 **query** (`string`): 全文搜索查询字符串 **paths** (`string[]`): 要搜索的字段路径(例如 \["note", "description"]) **topK** (`number`): 要返回的结果数量 (Default: `10`) **filter** (`Record`): 元数据筛选条件(应用于 metadata 字段) **metadataMode** (`'field' | 'document'`): 'field'(默认值)会投影托管的 metadata/document 字段。'document' 将完整源文档作为 metadata 返回。 (Default: `field`) **searchIndexName** (`string`): 覆盖此次调用解析出的全文搜索索引名称。默认使用 createSearchIndex() / createIndex() 持久化的索引。 ```typescript const results = await store.textQuery({ indexName: 'precedents', query: 'shell company offshore', paths: ['note'], topK: 10, }) ``` ### `hybridQuery()` 使用 MongoDB 服务端的 `$rankFusion` 运行融合 Vector 相似度与全文结果的混合搜索。它要求 MongoDB >= 8.0,并从 8.1 起正式可用。在 8.0.x 上,可能需要提交 MongoDB 支持工单才能启用;启用后即可运行,例如 Atlas 8.0.x。必须存在全文搜索索引:托管索引会自动创建;对于自带集合,则必须先调用 `createSearchIndex()`(主动选择)。 **indexName** (`string`): 要搜索的 Mastra 索引名称 **queryVector** (`number[]`): 相似度搜索使用的查询 Vector **query** (`string`): 全文搜索查询字符串 **paths** (`string[]`): 全文搜索要使用的字段路径(例如 \["note", "description"]) **topK** (`number`): 要返回的结果数量 (Default: `10`) **filter** (`Record`): 元数据筛选条件(应用于 Vector 和文本两个分支) **weights** (`{ vector?: number; text?: number }`): 融合时 Vector 结果与文本结果的相对权重(默认值:1:1) **numCandidates** (`number`): Vector 搜索分支的候选项数量 (Default: `20 * topK (capped at 10000)`) **metadataMode** (`'field' | 'document'`): 'field'(默认值)会投影托管的 metadata/document 字段。'document' 将完整源文档作为 metadata 返回。 (Default: `field`) **textSearchIndexName** (`string`): 覆盖此次调用解析出的全文搜索索引名称。默认使用 createSearchIndex() / createIndex() 持久化的索引。 ```typescript 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()` 的 `$rankFusion` 阶段要求 MongoDB >= 8.0。该阶段从 8.1 起正式可用。在 8.0.x 上,可能需要提交 MongoDB 支持工单才能启用;启用后即可运行,例如 Atlas 8.0.x。如果你运行的是更旧版本,或者 8.0.x 部署未启用 `$rankFusion`,请分别使用 `query()` 和 `textQuery()`,并在客户端合并结果。 ### `describeIndex()` 返回索引(集合)的信息。 **indexName** (`string`): 要描述的集合名称 返回: ```typescript interface IndexStats { dimension: number count: number metric: 'cosine' | 'euclidean' | 'dotproduct' } ``` ### `deleteIndex()` 删除 Vector 索引。具体行为取决于索引的创建方式: - **托管索引**(未使用 `collectionName` 创建):删除整个集合及其所有数据。 - **自带索引**(使用 `collectionName` 创建):删除 Atlas vectorSearch 索引;如果通过 `createSearchIndex()` 配置了配套的全文搜索索引,也会将其删除。调用方的业务集合及其文档会保留。该存储绝不会删除并非由它创建的集合。 创建索引时会持久记录 BYO 分类,因此即使由不同进程操作也能正确应用(例如,由设置作业创建索引,之后由长期运行的服务删除)。请始终传入**逻辑索引名称**(即 `indexName`,调用 `createIndex` 时使用的值),而不是物理集合名称。 **indexName** (`string`): 要删除的索引逻辑名称 ### `listIndexes()` 列出 Mastra 的**逻辑**索引名称(即 `indexName` 值,也就是传给 `createIndex` 的值),而不是物理集合名称。对于数据位于业务集合中的自带索引,返回逻辑索引名称,而不是物理集合名称。该值可直接传回 `deleteIndex()` / `describeIndex()`。在引入持久元数据之前创建的托管索引仍会通过其 `${name}_vector_index` 搜索索引被发现。内部注册表集合绝不会列出。 返回:`Promise` ### `updateVector()` 按 ID 或元数据筛选条件更新单个 Vector。必须提供 `id` 或 `filter`,但不能同时提供两者。 > **自带集合默认为只读。** `upsert()`、`updateVector()`、`deleteVector()` 和 `deleteVectors()` 会在 BYO 索引上抛出 USER 类别错误,除非创建索引时设置了 `allowWrites: true`。请参阅[为现有集合建立索引](#indexing-an-existing-collection)。 **indexName** (`string`): 包含该 Vector 的集合名称 **id** (`string`): 要更新的 Vector 条目 ID(与 filter 互斥) **filter** (`Record`): 用于识别待更新 Vector 的元数据筛选条件(与 id 互斥) **update** (`object`): 包含 Vector 和/或元数据的更新数据 **update.vector** (`number[]`): 要更新的新 Vector 数据 **update.metadata** (`Record`): 要更新的新元数据 ### `deleteVector()` 按 ID 从索引中删除指定的 Vector 条目。 **indexName** (`string`): 包含该 Vector 的集合名称 **id** (`string`): 要删除的 Vector 条目 ID ### `deleteVectors()` 按 ID 或元数据筛选条件删除多个 Vector。必须提供 `ids` 或 `filter`,但不能同时提供两者。 **indexName** (`string`): 包含待删除 Vector 的集合名称 **ids** (`string[]`): 要删除的 Vector ID 数组(与 filter 互斥) **filter** (`Record`): 用于识别待删除 Vector 的元数据筛选条件(与 ids 互斥) ### `disconnect()` 关闭 MongoDB 客户端连接。存储使用完毕后应调用此方法。 ## 响应类型 查询结果以以下格式返回: ```typescript interface QueryResult { id: string score: number metadata: Record vector?: number[] // Only included if includeVector is true } ``` ## 错误处理 该存储会抛出可捕获的类型化错误: ```typescript 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) } } ``` ## 为现有集合建立索引 你可以在现有业务集合上创建 Vector 索引,而不使用托管集合。需要为 MongoDB 数据库中的现有文档添加 Vector 搜索功能时,这种方式很有用。 ```typescript 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'] }) ``` **重要说明:** - 集合必须已经存在,并包含具有 `embedding` 字段(或你配置的自定义 `embeddingFieldPath`)的文档 - 使用 `collectionName` 时,绝不会创建或删除该集合 - **BYO 索引默认为只读。** `upsert()`、`updateVector()`、`deleteVector()` 和 `deleteVectors()` 会抛出明确错误,而不会修改调用方拥有的业务文档。若要允许该存储向集合写入嵌入(或从集合中删除文档),请通过 `createIndex({ ..., allowWrites: true })` 显式启用。该策略会持久化,重启后仍然有效。旧版本未设置此标志时写入的条目将按只读方式处理(故障时关闭)。 - 查询时使用 `metadataMode: 'document'` 可将完整源文档作为 `metadata` 检索 - 在 `'document'` 模式下,默认从 `metadata` 中省略嵌入;传入 `includeVector: true` 可将其保留(同时将其作为顶层 `vector` 公开) - **`'document'` 模式下的筛选作用于根文档字段**,而不是嵌套的 `metadata.` 子文档。`filter: { lane: 'fraud' }` 匹配业务文档的顶层 `lane` 字段(在默认的 `'field'` 模式下,对于托管集合,裸字段会重写为 `metadata.`)。下推路径和 `$match` 回退路径都遵循此行为。 - **支持原生 `ObjectId` `_id`。** 业务集合通常使用 `ObjectId` 作为键;查询结果会将 `_id` 强制转换为字符串(遵循 `QueryResult.id` 契约),`deleteVector()`/`updateVector()`/`deleteVectors()` 可接受该字符串并匹配底层 `ObjectId` 文档。托管集合(字符串 `_id`)不受影响。 - BYO 集合上的全文和混合搜索需要**主动启用**:不会自动创建全文索引,因此请先调用 `createSearchIndex()`,再调用 `textQuery()`/`hybridQuery()`。全文索引异步构建。立即执行文本/混合查询前,请调用 `waitForSearchIndexReady()`(或传入 `waitUntilReady: true`)。 - BYO 索引上的 `deleteIndex()` 会删除 Vector 索引(如果已创建文本索引,也会将其删除),但会**保留**集合及其文档 ## 最佳实践 - 为筛选条件中使用的元数据字段建立索引,以获得最佳查询性能。 - 在元数据中使用一致的字段命名,避免产生意外的查询结果。 - 定期监控索引和集合统计信息,确保搜索高效。 - 为现有集合建立索引时,请确保所有文档都包含必需的 `embedding` 字段。 ## 用法示例 ### 使用 `MongoDB` 的 Vector 嵌入 嵌入是 memory 的 `semanticRecall` 用来按语义(而非关键词)检索相关消息的数值 Vector。 > **备注:** 生产环境建议使用 MongoDB Atlas Vector Search。对于自托管部署,可以通过[使用 Atlas CLI 进行本地 Atlas 部署](https://www.mongodb.com/docs/atlas/cli/current/atlas-cli-deploy-local/)来使用 Vector Search。 此设置使用本地嵌入模型 FastEmbed 生成 Vector 嵌入。 如需使用,请安装 `@mastra/fastembed`: **npm**: ```bash npm install @mastra/fastembed@latest ``` **pnpm**: ```bash pnpm add @mastra/fastembed@latest ``` **Yarn**: ```bash yarn add @mastra/fastembed@latest ``` **Bun**: ```bash bun add @mastra/fastembed@latest ``` 将以下内容添加到 Agent: ```typescript 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 }, }), }) ``` ### 使用 VoyageAI 的 Vector 嵌入 VoyageAI 提供针对检索任务优化的专用嵌入模型。VoyageAI 还与 MongoDB Atlas 集成,可用于多模态嵌入。 **npm**: ```bash npm install @mastra/voyageai@latest ``` **pnpm**: ```bash pnpm add @mastra/voyageai@latest ``` **Yarn**: ```bash yarn add @mastra/voyageai@latest ``` **Bun**: ```bash bun add @mastra/voyageai@latest ``` 基本用法示例: ```typescript 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, }, }, }), }) ``` 有关 VoyageAI 嵌入的详细示例(包括专用模型、多模态嵌入和检索优化),请参阅 [VoyageAI 嵌入文档](https://mastra.zisheng.pro/models/embeddings)。 ## 相关内容 - [元数据筛选](https://mastra.zisheng.pro/reference/rag/metadata-filters) - [VoyageAI 嵌入文档](https://mastra.zisheng.pro/models/embeddings)