MongoDB Vector 存储
MongoDBVector 类使用 MongoDB Atlas Vector Search 提供 Vector 搜索。它支持在 MongoDB 集合中进行高效的相似度搜索和元数据筛选。
安装安装的直接链接
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/mongodb@latest
pnpm add @mastra/mongodb@latest
yarn add @mastra/mongodb@latest
bun add @mastra/mongodb@latest
用法示例用法示例的直接链接
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 选项:
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:
uri:
dbName:
options?:
embeddingFieldPath?:
方法方法的直接链接
connect()connect的直接链接
建立与 MongoDB 服务器的连接。首次使用时会自动调用,也可在需要时显式调用。
await store.connect()
createIndex()createindex的直接链接
在 MongoDB 中创建新的 Vector 索引(集合)。
indexName:
dimension:
metric?:
filterFields?:
metadata.<field>)。仅筛选已声明字段的查询会直接下推到 $vectorSearch,而不是预先筛选候选 _id,从而避免大型结果集的 16 MB BSON 限制。引用未声明字段或使用 $vectorSearch 不支持的运算符时,会自动回退到预筛选。collectionName?:
indexName。searchIndexName?:
${indexName}_vector_index。allowWrites?:
upsert、updateVector、deleteVector、deleteVectors)。BYO 索引默认为只读:该存储绝不会修改或删除调用方拥有的业务文档。托管集合始终可写,因此会忽略此选项。该策略随索引注册持久化,重启后仍然有效。waitForIndexReady()waitforindexready的直接链接
等待索引在创建后进入就绪状态。需要在执行操作前确保索引已就绪时,此方法很有用。
indexName:
timeoutMs?:
checkIntervalMs?:
upsert()upsert的直接链接
在集合中添加或更新 Vector 及其元数据。对于自带索引,这要求将 allowWrites: true 传给 createIndex(),因为 BYO 集合默认为只读。
indexName:
vectors:
metadata?:
ids?:
documents?:
query()query的直接链接
搜索相似 Vector,并可选择使用元数据筛选。
indexName:
queryVector:
topK?:
filter?:
metadata 字段)documentFilter?:
includeVector?:
numCandidates?:
metadataMode?:
'field'(默认值)会投影托管的 metadata/document 字段,并将 filter 字段与 metadata 子文档匹配。'document' 将完整源文档作为 metadata 返回,适用于文档结构自定义的自带业务集合;filter 字段会与**根**文档匹配(无 metadata. 前缀)。默认从 metadata 中省略嵌入字段(以避免负载过大);设置 includeVector: true 可在 metadata 中保留该字段,并将其作为顶层 vector 公开。createSearchIndex()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:
fields?:
searchIndexName?:
fields 但省略此项时,会使用每个逻辑索引唯一且互不相同的默认名称,这样字段映射就不会被自动创建的动态索引遮蔽,并且同一集合上的两个逻辑索引不会发生冲突。waitUntilReady?:
waitForSearchIndexReady()。await store.createSearchIndex({
indexName: 'precedents',
fields: ['note', 'description'],
})
字段映射索引名称包含逻辑 indexName,因此同一集合上的两个逻辑索引会获得不同的文本索引。使用不同的 fields 重新创建_同一个_逻辑索引时,仍需先删除现有索引(IndexAlreadyExists)。
waitForSearchIndexReady()waitforsearchindexready的直接链接
等待索引的全文(BM25)搜索索引变为 READY。waitForIndexReady() 只轮询 vectorSearch 索引;Atlas Search 全文索引仍在构建时 createSearchIndex() 就会返回,因此立即调用 textQuery()/hybridQuery() 可能间歇性失败。调用此方法(或将 waitUntilReady: true 传给 createSearchIndex())可阻塞至解析出的文本索引报告 READY。
indexName:
searchIndexName?:
timeoutMs?:
checkIntervalMs?:
await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] })
await store.waitForSearchIndexReady({ indexName: 'precedents' })
textQuery()textquery的直接链接
对 Atlas Search 索引运行全文(BM25)搜索。默认情况下,它以为此索引记录的文本搜索索引为目标(由 createSearchIndex() 设置,或动态 ${collectionName}_search_index,后者由 createIndex() 自动创建)。传入 searchIndexName 可将此次调用指向特定索引。
此处的元数据筛选条件(与 hybridQuery() 一样)通过 $match 阶段应用。对于 hybridQuery() 的 Vector 分支,在创建索引时未通过 filterFields 声明的字段筛选条件会透明地具体化为候选 _id(与 query() 使用的回退机制相同),因此未声明字段的筛选不会报错。
indexName:
query:
paths:
topK?:
filter?:
metadata 字段)metadataMode?:
'field'(默认值)会投影托管的 metadata/document 字段。'document' 将完整源文档作为 metadata 返回。searchIndexName?:
createSearchIndex() / createIndex() 持久化的索引。const results = await store.textQuery({
indexName: 'precedents',
query: 'shell company offshore',
paths: ['note'],
topK: 10,
})
hybridQuery()hybridquery的直接链接
使用 MongoDB 服务端的 $rankFusion 运行融合 Vector 相似度与全文结果的混合搜索。它要求 MongoDB >= 8.0,并从 8.1 起正式可用。在 8.0.x 上,可能需要提交 MongoDB 支持工单才能启用;启用后即可运行,例如 Atlas 8.0.x。必须存在全文搜索索引:托管索引会自动创建;对于自带集合,则必须先调用 createSearchIndex()(主动选择)。
indexName:
queryVector:
query:
paths:
topK?:
filter?:
weights?:
numCandidates?:
metadataMode?:
'field'(默认值)会投影托管的 metadata/document 字段。'document' 将完整源文档作为 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() 的 $rankFusion 阶段要求 MongoDB >= 8.0。该阶段从 8.1 起正式可用。在 8.0.x 上,可能需要提交 MongoDB 支持工单才能启用;启用后即可运行,例如 Atlas 8.0.x。如果你运行的是更旧版本,或者 8.0.x 部署未启用 $rankFusion,请分别使用 query() 和 textQuery(),并在客户端合并结果。
describeIndex()describeindex的直接链接
返回索引(集合)的信息。
indexName:
返回:
interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}
deleteIndex()deleteindex的直接链接
删除 Vector 索引。具体行为取决于索引的创建方式:
- 托管索引(未使用
collectionName创建):删除整个集合及其所有数据。 - 自带索引(使用
collectionName创建):删除 Atlas vectorSearch 索引;如果通过createSearchIndex()配置了配套的全文搜索索引,也会将其删除。调用方的业务集合及其文档会保留。该存储绝不会删除并非由它创建的集合。
创建索引时会持久记录 BYO 分类,因此即使由不同进程操作也能正确应用(例如,由设置作业创建索引,之后由长期运行的服务删除)。请始终传入逻辑索引名称(即 indexName,调用 createIndex 时使用的值),而不是物理集合名称。
indexName:
listIndexes()listindexes的直接链接
列出 Mastra 的逻辑索引名称(即 indexName 值,也就是传给 createIndex 的值),而不是物理集合名称。对于数据位于业务集合中的自带索引,返回逻辑索引名称,而不是物理集合名称。该值可直接传回 deleteIndex() / describeIndex()。在引入持久元数据之前创建的托管索引仍会通过其 ${name}_vector_index 搜索索引被发现。内部注册表集合绝不会列出。
返回:Promise<string[]>
updateVector()updatevector的直接链接
按 ID 或元数据筛选条件更新单个 Vector。必须提供 id 或 filter,但不能同时提供两者。
自带集合默认为只读。
upsert()、updateVector()、deleteVector()和deleteVectors()会在 BYO 索引上抛出 USER 类别错误,除非创建索引时设置了allowWrites: true。请参阅为现有集合建立索引。
indexName:
id?:
filter?:
update:
update.vector?:
update.metadata?:
deleteVector()deletevector的直接链接
按 ID 从索引中删除指定的 Vector 条目。
indexName:
id:
deleteVectors()deletevectors的直接链接
按 ID 或元数据筛选条件删除多个 Vector。必须提供 ids 或 filter,但不能同时提供两者。
indexName:
ids?:
filter?:
disconnect()disconnect的直接链接
关闭 MongoDB 客户端连接。存储使用完毕后应调用此方法。
响应类型响应类型的直接链接
查询结果以以下格式返回:
interface QueryResult {
id: string
score: number
metadata: Record<string, any>
vector?: number[] // Only included if includeVector is true
}
错误处理错误处理的直接链接
该存储会抛出可捕获的类型化错误:
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 搜索功能时,这种方式很有用。
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.<field>)。下推路径和$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 嵌入vector-embeddings-with-mongodb的直接链接
嵌入是 memory 的 semanticRecall 用来按语义(而非关键词)检索相关消息的数值 Vector。
生产环境建议使用 MongoDB Atlas Vector Search。对于自托管部署,可以通过使用 Atlas CLI 进行本地 Atlas 部署来使用 Vector Search。
此设置使用本地嵌入模型 FastEmbed 生成 Vector 嵌入。
如需使用,请安装 @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
将以下内容添加到 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
},
}),
})
使用 VoyageAI 的 Vector 嵌入使用 VoyageAI 的 Vector 嵌入的直接链接
VoyageAI 提供针对检索任务优化的专用嵌入模型。VoyageAI 还与 MongoDB Atlas 集成,可用于多模态嵌入。
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/voyageai@latest
pnpm add @mastra/voyageai@latest
yarn add @mastra/voyageai@latest
bun add @mastra/voyageai@latest
基本用法示例:
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 嵌入文档。