MongoDB 向量儲存
MongoDBVector 類別使用 MongoDB Atlas Vector Search 提供向量搜尋,讓你能在 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,
})
自訂 embedding 欄位路徑自訂 embedding 欄位路徑 的直接連結
如需將 embedding 儲存在巢狀欄位結構中(例如與現有 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 中建立新的向量索引(集合)。
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 的直接連結
在集合中新增或更新向量及其元數據。對自攜索引而言,由於 BYO 集合預設為唯讀,因此建立 createIndex() 時必須設定 allowWrites: true。
indexName:
vectors:
metadata?:
ids?:
documents?:
query()query 的直接連結
搜尋相似向量,並可選擇套用元數據篩選。
indexName:
queryVector:
topK?:
filter?:
metadata 欄位)documentFilter?:
includeVector?:
numCandidates?:
metadataMode?:
'field'(預設)會投影受管理的 metadata/document 欄位,而 filter 欄位會與 metadata 子文件比對。'document' 會將完整來源文件作為 metadata 傳回——適合文件具有自訂結構的自攜運作中集合——而 filter 欄位會與**根層文件**比對(不加 metadata. 前綴)。預設會從 metadata 略去 embedding 欄位(避免承載資料過大);設定 includeVector: true 可將其保留在 metadata,並同時公開為頂層 vector。createSearchIndex()createsearchindex 的直接連結
在索引所用的集合上配置 Atlas Search(BM25/全文)索引,並將其記錄為 textQuery() 和 hybridQuery() 所用的文字搜尋索引。
受管理集合與自攜集合:
- 對於受管理索引(建立時未提供 collectionName),
createIndex()已配置名為${collectionName}_search_index的_動態_全文索引(涵蓋所有字串欄位)。因此,只有需要限制欄位的 mapping 或自訂索引名稱時,才需要使用createSearchIndex()。 - 對於自攜索引(建立時提供
collectionName),createIndex()不會自動建立任何全文索引。在呼叫者擁有的運作中集合上啟用textQuery()/hybridQuery()屬於選擇加入。請明確呼叫createSearchIndex()以配置(需付費的)文字索引。在此之前,textQuery()/hybridQuery()會擲回清晰錯誤,而不會查詢不存在的索引。
命名方式:
- 提供
fields但未明確提供searchIndexName時,欄位 mapping 索引會使用一個不同的預設名稱(${collectionName}_${indexName}_search_fields_index,每個邏輯索引皆為唯一),避免與受管理集合自動建立的動態索引衝突並遭無聲忽略。這個不同的索引會持久保存為文字搜尋索引,因此textQuery()/hybridQuery()會自動使用受限制的 mapping。 - 提供
searchIndexName時,會使用並持久保存該確切名稱。textQuery()/hybridQuery()會自動解析已保存的名稱。你亦可透過各次呼叫的searchIndexName/textSearchIndexName參數覆寫名稱。
indexName:
fields?:
searchIndexName?:
fields 而略去此項,會使用每個邏輯索引獨有的不同預設名稱,確保欄位 mapping 不會被自動建立的動態索引遮蓋,且同一集合上的兩個邏輯索引不會互相衝突。waitUntilReady?:
waitForSearchIndexReady()。await store.createSearchIndex({
indexName: 'precedents',
fields: ['note', 'description'],
})
欄位 mapping 索引名稱包含邏輯 indexName,因此同一集合上的兩個邏輯索引會有不同的文字索引。使用不同 fields 重新建立_同一個_邏輯索引時,仍須先移除現有索引(IndexAlreadyExists)。
waitForSearchIndexReady()waitforsearchindexready 的直接連結
等待某索引的全文(BM25)搜尋索引變為 READY。waitForIndexReady() 只會輪詢 vectorSearch 索引;createSearchIndex() 傳回時,Atlas Search 全文索引仍在建立,因此立即呼叫 textQuery()/hybridQuery() 可能間歇性失敗。呼叫此方法(或向 createSearchIndex() 傳入 waitUntilReady: true)可封鎖至解析出的文字索引回報 READY。
indexName:
searchIndexName?:
timeoutMs?:
checkIntervalMs?:
await store.createSearchIndex({ indexName: 'precedents', fields: ['note'] })
await store.waitForSearchIndexReady({ indexName: 'precedents' })
textQuery()textquery 的直接連結
對 Atlas Search 索引執行全文(BM25)搜尋。預設會以此索引記錄的文字搜尋索引為目標(由 createSearchIndex() 設定,或由 createIndex() 自動建立的動態 ${collectionName}_search_index)。傳入 searchIndexName 可指定這次呼叫要使用的索引。
此處的元數據篩選條件(與 hybridQuery() 相同)會透過 $match 階段套用。對 hybridQuery() 的向量分支而言,建立索引時未透過 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 融合向量相似度與全文結果。此功能需要 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 的直接連結
刪除向量索引。行為取決於索引的建立方式:
- 受管理索引(建立時未提供
collectionName):移除整個集合及其中所有資料。 - 自攜索引(建立時提供
collectionName):移除 Atlas vectorSearch 索引;如曾透過createSearchIndex()配置配套全文搜尋索引,亦會將其移除。呼叫者的運作中集合及其文件會予以保留。此儲存絕不會移除並非由其建立的集合。
建立索引時會持久記錄 BYO 分類,因此即使由另一個處理程序操作(例如索引由設定工作建立,其後由長期運行的服務刪除),仍會正確套用。請一律傳入邏輯索引名稱(在 createIndex 使用的 indexName),而非實體集合名稱。
indexName:
listIndexes()listindexes 的直接連結
列出邏輯 Mastra 索引名稱(傳入 createIndex 的 indexName 值),而非實體集合名稱。對資料位於運作中集合的自攜索引,會傳回邏輯索引名稱,而非實體集合名稱。該值可直接傳回 deleteIndex()/describeIndex()。在引入持久元數據前建立的受管理索引,仍可透過其 ${name}_vector_index 搜尋索引找到。內部登記集合絕不會列出。
傳回:Promise<string[]>
updateVector()updatevector 的直接連結
按 ID 或元數據篩選條件更新單一向量。必須提供 id 或 filter 其中之一,但不能同時提供兩者。
自攜集合預設為唯讀。 除非建立 BYO 索引時設定了
allowWrites: true,否則upsert()、updateVector()、deleteVector()和deleteVectors()會擲回 USER 類別錯誤。請參閱為現有集合建立索引。
indexName:
id?:
filter?:
update:
update.vector?:
update.metadata?:
deleteVector()deletevector 的直接連結
按 ID 從索引刪除特定向量項目。
indexName:
id:
deleteVectors()deletevectors 的直接連結
按 ID 或元數據篩選條件刪除多個向量。必須提供 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)
}
}
為現有集合建立索引為現有集合建立索引 的直接連結
你可在現有運作中集合上建立向量索引,而無需使用受管理集合。當你想為 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'] })
重要事項:
- 使用
collectionName時,集合必須已存在,並包含具有embedding欄位(或你設定的自訂embeddingFieldPath)的文件 - 使用
collectionName時,絕不會建立或移除集合 - BYO 索引預設為唯讀。
upsert()、updateVector()、deleteVector()和deleteVectors()會擲回清晰錯誤,而不會修改呼叫者擁有的運作中文件。如要讓儲存將 embedding 寫入你的集合(或從中刪除文件),請透過createIndex({ ..., allowWrites: true })明確選擇加入。此政策會持久保存,重新啟動後仍然生效。由沒有該旗標的舊版本寫入的項目會視為唯讀(失敗時保持關閉)。 - 查詢時使用
metadataMode: 'document',可將完整來源文件擷取為metadata - 在
'document'模式中,預設會從metadata略去 embedding;傳入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 集合的全文及混合搜尋屬於選擇加入:不會自動建立全文索引,因此請在使用
textQuery()/hybridQuery()前呼叫createSearchIndex()。全文索引會以非同步方式建立。立即執行文字/混合查詢前,請呼叫waitForSearchIndexReady()(或傳入waitUntilReady: true)。 - BYO 索引的
deleteIndex()會移除向量索引(以及已建立的文字索引),但會保留集合及其文件
最佳做法最佳做法 的直接連結
- 為篩選條件使用的元數據欄位建立索引,以取得最佳查詢效能。
- 在元數據中使用一致的欄位命名,避免出現非預期的查詢結果。
- 定期監察索引和集合統計資料,確保搜尋效率。
- 為現有集合建立索引時,請確保所有文件均具有所需的
embedding欄位。
使用範例使用範例 的直接連結
使用 MongoDB 的向量 embeddingvector-embeddings-with-mongodb 的直接連結
Embedding 是數值向量,memory 的 semanticRecall 會使用它按語意(而非關鍵字)擷取相關訊息。
建議在生產環境使用 MongoDB Atlas Vector Search。對自行託管的部署,可透過 Atlas CLI 的本機 Atlas 部署使用 Vector Search。
此設定使用本機 embedding 模型 FastEmbed 產生向量 embedding。
要使用此設定,請安裝 @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 的向量 embedding使用 VoyageAI 的向量 embedding 的直接連結
VoyageAI 提供針對擷取工作最佳化的專門 embedding 模型。VoyageAI 亦已與 MongoDB Atlas 整合,可用於多模態 embedding。
- 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 embedding 的詳細範例(包括專門模型、多模態 embedding 和擷取最佳化),請參閱 VoyageAI embedding 文件。