跳至主要內容

MongoDB 向量儲存

MongoDBVector 類別使用 MongoDB Atlas Vector Search 提供向量搜尋。它可在 MongoDB 集合中進行高效率的相似度搜尋與中繼資料篩選。

安裝
「安裝」的直接連結

npm install @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:

string
此向量儲存執行個體的不重複識別碼

uri:

string
MongoDB 連線字串

dbName:

string
要使用的 MongoDB 資料庫名稱

options?:

MongoClientOptions
選用的 MongoDB 使用者端選項

embeddingFieldPath?:

string
= embedding
儲存向量嵌入的欄位路徑。支援使用點號標記法的巢狀路徑(例如 'text.contentEmbedding')。

方法
「方法」的直接連結

connect()
「connect」的直接連結

建立與 MongoDB 伺服器的連線。首次使用時會自動呼叫此方法,但也可視需要明確呼叫。

await store.connect()

createIndex()
「createindex」的直接連結

在 MongoDB 中建立新的向量索引(集合)。

indexName:

string
要建立的集合名稱

dimension:

number
向量維度(必須與嵌入模型相符)

metric?:

'cosine' | 'euclidean' | 'dotproduct'
= cosine
相似度搜尋使用的距離度量

filterFields?:

string[]
要在 Atlas vectorSearch 索引中宣告為篩選欄位的中繼資料欄位名稱(註冊為 metadata.<field>)。只篩選已宣告欄位的查詢會直接下推至 $vectorSearch,而不會預先篩選候選 _id,藉此避免大型結果集的 16 MB BSON 限制。若篩選條件參照未宣告的欄位,或使用 $vectorSearch 不支援的運算子,則會自動改用預先篩選。

collectionName?:

string
將向量儲存在現有的作業集合中,而非使用以索引命名的受管理集合。設定此選項後,此儲存絕不會建立或移除該集合。預設為 indexName

searchIndexName?:

string
在集合上建立的 Atlas vectorSearch 索引名稱。預設為 ${indexName}_vector_index

allowWrites?:

boolean
= false
選擇允許對自備集合執行寫入操作(upsertupdateVectordeleteVectordeleteVectors)。BYO 索引預設為唯讀:此儲存絕不會修改或刪除呼叫端擁有的作業文件。受管理集合一律可寫入,因此會忽略此選項。此原則會隨索引註冊持久保存,重新啟動後仍然有效。

waitForIndexReady()
「waitforindexready」的直接連結

等待建立後的索引進入就緒狀態。需要在執行操作前確保索引已就緒時很實用。

indexName:

string
要等待的索引名稱

timeoutMs?:

number
= 60000
最長等待時間,單位為毫秒

checkIntervalMs?:

number
= 2000
狀態檢查間隔,單位為毫秒

upsert()
「upsert」的直接連結

在集合中新增或更新向量及其中繼資料。BYO 集合預設為唯讀,因此若使用自備索引,必須在呼叫 createIndex() 時設定 allowWrites: true

indexName:

string
要插入資料的集合名稱

vectors:

number[][]
嵌入向量陣列

metadata?:

Record<string, any>[]
每個向量的中繼資料

ids?:

string[]
選用的向量 ID(未提供時會自動產生)

documents?:

string[]
選用的文件文字內容,與向量一併儲存

query()
「query」的直接連結

搜尋相似向量,並可選擇套用中繼資料篩選。

indexName:

string
要搜尋的集合名稱

queryVector:

number[]
用於尋找相似向量的查詢向量

topK?:

number
= 10
要傳回的結果數量

filter?:

Record<string, any>
中繼資料篩選條件(套用至 metadata 欄位)

documentFilter?:

Record<string, any>
針對原始文件欄位的篩選條件(不限於中繼資料)

includeVector?:

boolean
= false
結果是否包含向量資料

numCandidates?:

number
= 20 * topK (capped at 10000)
HNSW 圖形在選出 top-K 結果前納入考量的候選項目數量。較高的值可提高召回率,但會增加延遲。請參閱:https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/

metadataMode?:

'field' | 'document'
= field
'field'(預設)會投影受管理的 metadatadocument 欄位,並將 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() 會自動解析已保存的名稱。你也可以透過各方法的 searchIndexNametextSearchIndexName 參數,在每次呼叫時覆寫名稱。

indexName:

string
其集合要建立搜尋索引的 Mastra 索引名稱

fields?:

string[]
全文搜尋要建立索引的欄位名稱。省略時使用動態對應(所有字串欄位)。

searchIndexName?:

string
= ${collectionName}_search_index(提供 `fields` 時則為 ${collectionName}_${indexName}_search_fields_index)
Atlas Search 索引名稱。提供 fields 且省略此值時,會使用每個邏輯索引都不重複的獨立預設名稱,因此欄位對應不會被自動建立的動態索引遮蔽,同一集合上的兩個邏輯索引也不會衝突。

waitUntilReady?:

boolean
= false
設為 true 時,會阻塞到已佈建的全文索引回報 READY 後才完成。預設為 false,以避免非預期延遲;若偏好分開等待,請明確呼叫 waitForSearchIndexReady()
await store.createSearchIndex({
indexName: 'precedents',
fields: ['note', 'description'],
})

欄位對應索引名稱包含邏輯 indexName,因此同一集合上的兩個邏輯索引會有不同的文字索引。若要使用不同 fields 重新建立_同一個_邏輯索引,仍須先移除現有索引(IndexAlreadyExists)。

waitForSearchIndexReady()
「waitforsearchindexready」的直接連結

等待索引的全文(BM25)搜尋索引進入 READY 狀態。waitForIndexReady() 只會輪詢 vectorSearch 索引;createSearchIndex() 會在 Atlas Search 全文索引仍在建置時傳回,因此立即呼叫 textQuery()hybridQuery() 可能偶爾失敗。請呼叫此方法(或將 waitUntilReady: true 傳給 createSearchIndex()),阻塞到解析出的文字索引回報 READY。

indexName:

string
其文字索引要等待的索引邏輯名稱

searchIndexName?:

string
覆寫解析出的文字搜尋索引名稱

timeoutMs?:

number
= 60000
最長等待時間,單位為毫秒

checkIntervalMs?:

number
= 2000
狀態檢查間隔,單位為毫秒
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:

string
要搜尋的 Mastra 索引名稱

query:

string
全文搜尋查詢字串

paths:

string[]
要搜尋的欄位路徑(例如 ["note", "description"])

topK?:

number
= 10
要傳回的結果數量

filter?:

Record<string, any>
中繼資料篩選條件(套用至 metadata 欄位)

metadataMode?:

'field' | 'document'
= field
'field'(預設)會投影受管理的 metadatadocument 欄位。'document' 會以 metadata 傳回完整來源文件。

searchIndexName?:

string
覆寫本次呼叫所解析出的全文搜尋索引名稱。預設為 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:

string
要搜尋的 Mastra 索引名稱

queryVector:

number[]
相似度搜尋使用的查詢向量

query:

string
全文搜尋查詢字串

paths:

string[]
全文搜尋使用的欄位路徑(例如 ["note", "description"])

topK?:

number
= 10
要傳回的結果數量

filter?:

Record<string, any>
中繼資料篩選條件(同時套用至向量與文字分支)

weights?:

{ vector?: number; text?: number }
融合時向量結果與文字結果的相對權重(預設:1:1)

numCandidates?:

number
= 20 * topK (capped at 10000)
向量搜尋分支的候選項目數量

metadataMode?:

'field' | 'document'
= field
'field'(預設)會投影受管理的 metadatadocument 欄位。'document' 會以 metadata 傳回完整來源文件。

textSearchIndexName?:

string
覆寫本次呼叫所解析出的全文搜尋索引名稱。預設為 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:

string
要描述的集合名稱

傳回:

interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}

deleteIndex()
「deleteindex」的直接連結

刪除向量索引。行為取決於索引的建立方式:

  • 受管理索引(建立時未提供 collectionName):移除整個集合及其中所有資料。
  • 自備索引(建立時提供 collectionName):移除 Atlas vectorSearch 索引,以及透過 createSearchIndex() 佈建的配套全文搜尋索引(若有)。呼叫端的作業集合及其中的文件會保留。此儲存絕不會移除非由它建立的集合。

建立索引時會持久記錄 BYO 分類,因此即使由不同處理程序操作,也能正確套用(例如由設定工作建立索引,之後再由長期執行的服務刪除)。請一律傳入邏輯索引名稱(呼叫 createIndex 時使用的 indexName),而不是實體集合名稱。

indexName:

string
要刪除的索引邏輯名稱

listIndexes()
「listindexes」的直接連結

列出 Mastra 的邏輯索引名稱(傳給 createIndexindexName 值),而不是實體集合名稱。對於資料位於作業集合中的自備索引,會傳回邏輯索引名稱,而非實體集合名稱。此值可直接傳給 deleteIndex()describeIndex()。在引入持久中繼資料前建立的受管理索引,仍可透過其 ${name}_vector_index 搜尋索引找到。內部登錄集合絕不會列出。

傳回:Promise<string[]>

updateVector()
「updatevector」的直接連結

依 ID 或中繼資料篩選條件更新單一向量。必須提供 idfilter 其中一項,但不能同時提供兩者。

**自備集合預設為唯讀。**除非 BYO 索引建立時設定了 allowWrites: true,否則 upsert()updateVector()deleteVector()deleteVectors() 會擲回 USER 類別錯誤。請參閱為現有集合建立索引

indexName:

string
包含該向量的集合名稱

id?:

string
要更新的向量項目 ID(不可與 filter 同時使用)

filter?:

Record<string, any>
用於識別待更新向量的中繼資料篩選條件(不可與 id 同時使用)

update:

object
包含向量及/或中繼資料的更新資料

update.vector?:

number[]
要更新的新向量資料

update.metadata?:

Record<string, any>
要更新的新中繼資料

deleteVector()
「deletevector」的直接連結

依 ID 從索引中刪除指定的向量項目。

indexName:

string
包含該向量的集合名稱

id:

string
要刪除的向量項目 ID

deleteVectors()
「deletevectors」的直接連結

依 ID 或中繼資料篩選條件刪除多個向量。必須提供 idsfilter 其中一項,但不能同時提供兩者。

indexName:

string
包含待刪除向量的集合名稱

ids?:

string[]
要刪除的向量 ID 陣列(不可與 filter 同時使用)

filter?:

Record<string, any>
用於識別待刪除向量的中繼資料篩選條件(不可與 ids 同時使用)

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'] })

重要注意事項:

  • 集合必須已存在,且包含具 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 集合上的全文與混合搜尋是選擇啟用的功能:不會自動建立全文索引,因此請在 textQuery()hybridQuery() 前呼叫 createSearchIndex()。全文索引會以非同步方式建置。若要立即進行文字/混合查詢,請先呼叫 waitForSearchIndexReady()(或傳入 waitUntilReady: true)。
  • BYO 索引上的 deleteIndex() 會移除向量索引(以及已建立的文字索引),但會保留集合及其中的文件

最佳實務
「最佳實務」的直接連結

  • 為篩選條件使用的中繼資料欄位建立索引,以取得最佳查詢效能。
  • 在中繼資料中使用一致的欄位命名,以避免非預期的查詢結果。
  • 定期監控索引與集合的統計資料,以確保搜尋效率。
  • 為現有集合建立索引時,請確保所有文件都有必要的 embedding 欄位。

使用範例
「使用範例」的直接連結

使用 MongoDB 的向量嵌入
「vector-embeddings-with-mongodb」的直接連結

嵌入是記憶體的 semanticRecall 用來依語意(而非關鍵字)擷取相關訊息的數值向量。

備註

正式環境建議使用 MongoDB Atlas Vector Search。自行託管的部署可透過 Atlas CLI 的本機 Atlas 部署使用 Vector Search。

此設定使用本機嵌入模型 FastEmbed 產生向量嵌入。 若要使用,請安裝 @mastra/fastembed

npm install @mastra/fastembed@latest

將下列內容新增至你的 Agent:

src/mastra/agents/example-mongodb-agent.ts
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 的向量嵌入
「使用 VoyageAI 的向量嵌入」的直接連結

VoyageAI 提供針對擷取工作最佳化的專用嵌入模型。VoyageAI 也與 MongoDB Atlas 整合,可提供多模態嵌入。

npm install @mastra/voyageai@latest

基本使用範例:

src/mastra/agents/example-mongodb-voyageai-agent.ts
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 嵌入文件