儲存空間
儲存空間 API 已標準化,所有方法都使用一致的分頁與命名模式。
資料庫遷移「資料庫遷移」的直接連結
請透過一般遷移流程執行這些 SQL 遷移(例如 Prisma Migrate、Drizzle Kit,或 DBA 審查流程)。
Scorer 資料表欄位重新命名「Scorer 資料表欄位重新命名」的直接連結
mastra_scorers 中的 runtimeContext 欄位已重新命名為 requestContext。
只有在使用 @mastra/pg 或 @mastra/libsql 搭配 Evals/評分,而且 runtimeContext 欄位已有現有資料時才需要。
現有分數記錄的請求內容資料將無法存取。
部署 v1(初始化時會新增 requestContext 欄位)後,請複製資料並刪除舊欄位:
UPDATE mastra_scorers SET "requestContext" = "runtimeContext" WHERE "runtimeContext" IS NOT NULL;
ALTER TABLE mastra_scorers DROP COLUMN "runtimeContext";
重複 span 遷移「重複 span 遷移」的直接連結
如果從舊版 Mastra 升級,mastra_spans 資料表中可能有重複的 (traceId, spanId) 項目。V1 會為這些欄位新增唯一條件約束,以確保資料完整性,但若存在重複項目,就無法新增此條件約束。
只有在保有 Mastra v1 之前版本的現有 span 資料,而且遇到重複鍵違規或條件約束建立失敗錯誤時才需要。
儲存空間初始化可能會在嘗試新增唯一條件約束時失敗,或可能看到「duplicate key value violates unique constraint」等錯誤。
選項 1:使用 CLI(建議)「選項 1:使用 CLI(建議)」的直接連結
執行遷移命令,自動刪除重複 span 並新增條件約束:
npx mastra migrate
CLI 會封裝專案並連線至已設定的儲存空間,再執行遷移。移除重複項目時,會保留最完整的記錄(依 endTime 與屬性判斷)。
選項 2:手動執行 SQL(PostgreSQL)「選項 2:手動執行 SQL(PostgreSQL)」的直接連結
如果偏好手動執行遷移:
-- Remove duplicates, keeping the most complete record
DELETE FROM mastra_spans a USING mastra_spans b
WHERE a.ctid < b.ctid
AND a."traceId" = b."traceId"
AND a."spanId" = b."spanId";
-- Add the unique constraint
ALTER TABLE mastra_spans ADD CONSTRAINT mastra_spans_trace_span_unique UNIQUE ("traceId", "spanId");
選項 3:手動遷移(其他資料庫)「選項 3:手動遷移(其他資料庫)」的直接連結
對於 ClickHouse、LibSQL、MongoDB 或 MSSQL,請使用程式化 API:
const storage = mastra.getStorage()
const observabilityStore = await storage.getStore('observability')
// Check if migration is needed
const status = await observabilityStore?.checkSpansMigrationStatus()
console.log(status)
// Run the migration
const result = await observabilityStore?.migrateSpans()
console.log(result)
JSON 欄位(TEXT → JSONB)「JSON 欄位(TEXT → JSONB)」的直接連結
僅限 PostgreSQL。mastra_threads 的 metadata 欄位與 mastra_workflow_snapshot 的 snapshot 欄位已從 TEXT 變更為 JSONB。
遷移至 JSONB 後,即可使用 PostgreSQL 原生 JSON 運算子與 GIN 索引,提升 JSON 欄位的查詢效能。
ALTER TABLE mastra_threads
ALTER COLUMN metadata TYPE jsonb
USING metadata::jsonb;
ALTER TABLE mastra_workflow_snapshot
ALTER COLUMN snapshot TYPE jsonb
USING snapshot::jsonb;
已新增「已新增」的直接連結
在 MastraCompositeStore 中組合儲存空間「storage-composition-in-mastracompositestore」的直接連結
MastraCompositeStore 現在可以組合來自不同轉接器的儲存空間領域。不同用途需要使用不同資料庫時可使用它,例如 Memory 與 Workflow 使用 PostgreSQL,但可觀測性使用專用資料庫。
import { MastraCompositeStore } from '@mastra/core/storage'
import { MemoryPG, WorkflowsPG, ScoresPG } from '@mastra/pg'
import { MemoryLibSQL } from '@mastra/libsql'
import { Mastra } from '@mastra/core'
// Compose domains from different stores
const mastra = new Mastra({
storage: new MastraCompositeStore({
id: 'composite',
domains: {
memory: new MemoryLibSQL({ url: 'file:./local.db' }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
scores: new ScoresPG({ connectionString: process.env.DATABASE_URL }),
},
}),
})
詳情請參閱儲存空間組合參考文件。
已變更「已變更」的直接連結
MastraStorage 重新命名為 MastraCompositeStore「mastrastorage-renamed-to-mastracompositestore」的直接連結
MastraStorage 類別已重新命名為 MastraCompositeStore,更準確反映它作為複合儲存空間實作的角色:將不同領域路由至不同的底層儲存空間。這可避免與一般「Mastra Storage」概念(Mastra 執行個體上的 storage 屬性)混淆。
為維持回溯相容性,舊的 MastraStorage 名稱仍可作為已棄用的別名使用,但將在未來版本移除。
遷移時,請更新匯入與執行個體化方式:
- import { MastraStorage } from "@mastra/core/storage";
+ import { MastraCompositeStore } from "@mastra/core/storage";
import { MemoryLibSQL } from "@mastra/libsql";
import { WorkflowsPG } from "@mastra/pg";
export const mastra = new Mastra({
- storage: new MastraStorage({
+ storage: new MastraCompositeStore({
id: "composite",
domains: {
memory: new MemoryLibSQL({ url: "file:./memory.db" }),
workflows: new WorkflowsPG({ connectionString: process.env.DATABASE_URL }),
},
}),
});
如果直接使用單一儲存空間實作(例如 PostgresStore 或 LibSQLStore),請保留現有設定。這只會影響明確使用 MastraStorage 建立複合儲存空間的程式碼。
儲存空間執行個體必須使用 id 屬性「required-id-property-for-storage-instances」的直接連結
儲存空間執行個體現在必須使用 id 屬性。此唯一識別碼用來在 Mastra 中追蹤及管理儲存空間執行個體。應為應用程式中的每個儲存空間執行個體設定具描述性且不重複的 id 字串。
遷移時,請在儲存空間建構函式中新增 id 欄位。
const storage = new PostgresStore({
+ id: 'main-postgres-store',
connectionString: process.env.POSTGRES_CONNECTION_STRING,
schemaName: 'public',
});
const upstashStore = new UpstashStore({
+ id: 'upstash-cache-store',
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
分頁從 offset/limit 改為 page/perPage「pagination-from-offsetlimit-to-pageperpage」的直接連結
所有分頁 API 現在都使用 page 與 perPage,而非 offset 與 limit,以符合以頁面為基礎的網頁分頁方式。
遷移時,請將所有分頁參數從 offset/limit 更新為 page/perPage。請注意,page 從 0 開始。
memoryStore.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});
getMessagesPaginated 改為 listMessages「getmessagespaginated-to-listmessages」的直接連結
getMessagesPaginated() 方法已由 listMessages() 取代。新方法支援 perPage: false,可在不分頁的情況下擷取所有記錄。這項變更符合 list* 命名慣例,並增加擷取所有記錄的彈性。
遷移時,請重新命名方法並更新分頁參數。現在可以使用 perPage: false 擷取所有記錄。
+ const memoryStore = await storage.getStore('memory');
+
// Paginated
- const result = await storage.getMessagesPaginated({
+ const result = await memoryStore?.listMessages({
threadId: 'thread-123',
- offset: 0,
- limit: 20,
+ page: 0,
+ perPage: 20,
});
// Fetch all records (no pagination limit)
+ const allMessages = await memoryStore?.listMessages({
+ threadId: 'thread-123',
+ page: 0,
+ perPage: false,
+ });
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/storage-get-messages-paginated .
透過 getStore() 存取特定領域的儲存空間「domain-specific-storage-access-via-getstore」的直接連結
儲存空間作業現在會透過特定領域的儲存空間存取,而非直接在儲存空間執行個體上存取。
領域包括:
memory- 討論串、訊息與資源workflows- Workflow 快照scores- 評估分數observability- Trace 與 spanagents- 已儲存的 Agent 資料
遷移時,請使用領域名稱呼叫 getStore(),再呼叫所傳回儲存空間上的方法。
const storage = mastra.getStorage();
// Memory operations (threads, messages, resources)
- const thread = await storage.getThread({ threadId: '123' });
- await storage.saveThread({ thread });
+ const memoryStore = await storage.getStore('memory');
+ const thread = await memoryStore?.getThreadById({ threadId: '123' });
+ await memoryStore?.saveThread({ thread });
// Workflow operations (snapshots)
- const snapshot = await storage.loadWorkflowSnapshot({ runId, workflowName });
- await storage.persistWorkflowSnapshot({ runId, workflowName, snapshot });
+ const workflowStore = await storage.getStore('workflows');
+ const snapshot = await workflowStore?.loadWorkflowSnapshot({ runId, workflowName });
+ await workflowStore?.persistWorkflowSnapshot({ runId, workflowName, snapshot });
// Observability operations (traces, spans)
- const traces = await storage.listTraces({ page: 0, perPage: 20 });
+ const observabilityStore = await storage.getStore('observability');
+ const traces = await observabilityStore?.listTraces({ page: 0, perPage: 20 });
// Score operations (evaluations)
- const scores = await storage.listScoresByScorerId({ scorerId: 'helpfulness' });
+ const scoresStore = await storage.getStore('scores');
+ const scores = await scoresStore?.listScoresByScorerId({ scorerId: 'helpfulness' });
getThreadsByResourceId 改為 listThreads「getthreadsbyresourceid-to-listthreads」的直接連結
getThreadsByResourceId() 方法已由 listThreads() 取代。新方法新增分頁支援,並可依 resourceId、metadata 或兩者篩選。
舊的 getThreadsByResourceId() 會傳回所有相符討論串,且不分頁。新的 listThreads() 必須提供分頁參數。若要保留擷取所有討論串的舊有行為,請使用 perPage: false。
遷移時,請使用 Memory 儲存空間與新的 listThreads() 方法,並提供分頁與選填的篩選物件。
- const threads = await storage.getThreadsByResourceId({
- resourceId: 'res-123',
- });
+ const memoryStore = await storage.getStore('memory');
+
+ // Paginated (recommended for large datasets)
+ const result = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ page: 0,
+ perPage: 20,
+ });
+ const threads = result?.threads;
+
+ // Or fetch all threads like before (use perPage: false)
+ const allResult = await memoryStore?.listThreads({
+ filter: { resourceId: 'res-123' },
+ perPage: false,
+ });
+ const allThreads = allResult?.threads;
新方法也支援:
- 列出所有討論串(省略篩選條件)
- 僅依中繼資料篩選
- 結合 resourceId 與中繼資料篩選條件
// List all threads
await memoryStore?.listThreads({ page: 0, perPage: 20 })
// Filter by metadata only
await memoryStore?.listThreads({
filter: { metadata: { status: 'active' } },
page: 0,
perPage: 20,
})
// Combined filter
await memoryStore?.listThreads({
filter: {
resourceId: 'user-123',
metadata: { category: 'support' },
},
page: 0,
perPage: 20,
})
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/storage-list-threads-by-resource-to-list-threads .
getWorkflowRuns 改為 listWorkflowRuns「getworkflowruns-to-listworkflowruns」的直接連結
getWorkflowRuns() 方法已重新命名為 listWorkflowRuns()。這項變更符合 list* 方法傳回集合的慣例。
遷移時,請使用 Workflow 儲存空間、重新命名方法呼叫,並更新分頁參數。
- const runs = await storage.getWorkflowRuns({
+ const workflowStore = await storage.getStore('workflows');
+ const runs = await workflowStore?.listWorkflowRuns({
fromDate,
toDate,
+ page: 0,
+ perPage: 20,
});
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/storage-list-workflow-runs .
getMessagesById 改為 listMessagesById「getmessagesbyid-to-listmessagesbyid」的直接連結
getMessagesById() 方法已重新命名為 listMessagesById()。這項變更符合 list* 方法傳回集合的慣例。
遷移時,請使用 Memory 儲存空間並重新命名方法呼叫。
+ const memoryStore = await storage.getStore('memory');
- const result = await storage.getMessagesById({
+ const result = await memoryStore?.listMessagesById({
messageIds: ['msg-1', 'msg-2'],
});
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/storage-list-messages-by-id .
儲存空間 getMessages 與 saveMessages 簽章「storage-getmessages-and-savemessages-signatures」的直接連結
getMessages() 與 saveMessages() 方法的簽章與傳回型別已變更。格式多載已移除,方法現在一律使用 MastraDBMessage。這項變更移除格式變體,簡化 API。
遷移時,請使用 Memory 儲存空間、移除格式參數,並更新程式碼以使用一致的傳回型別。
+ const memoryStore = await storage.getStore('memory');
+
// Always returns { messages: MastraDBMessage[] }
- const v1Messages = await storage.getMessages({ threadId, format: 'v1' });
- const v2Messages = await storage.getMessages({ threadId, format: 'v2' });
+ const result = await memoryStore?.getMessages({ threadId });
+ const messages = result?.messages; // MastraDBMessage[]
// SaveMessages always uses MastraDBMessage
- await storage.saveMessages({ messages: v1Messages, format: 'v1' });
- await storage.saveMessages({ messages: v2Messages, format: 'v2' });
+ const saveResult = await memoryStore?.saveMessages({ messages: mastraDBMessages });
+ const saved = saveResult?.messages; // MastraDBMessage[]
向量儲存 API 從位置引數改為具名引數「向量儲存 API 從位置引數改為具名引數」的直接連結
所有向量儲存方法現在都使用引數物件,而非位置引數。這讓每個值的用途在呼叫位置清楚可見,也能讓方法簽章在不依賴引數順序的情況下演進。
遷移時,請更新所有向量儲存方法呼叫,改用引數物件。
- await vectorDB.createIndex(indexName, 3, 'cosine');
+ await vectorDB.createIndex({
+ indexName: indexName,
+ dimension: 3,
+ metric: 'cosine',
+ });
- await vectorDB.upsert(indexName, [[1, 2, 3]], [{ test: 'data' }]);
+ await vectorDB.upsert({
+ indexName: indexName,
+ vectors: [[1, 2, 3]],
+ metadata: [{ test: 'data' }],
+ });
- await vectorDB.query(indexName, [1, 2, 3], 5);
+ await vectorDB.query({
+ indexName: indexName,
+ queryVector: [1, 2, 3],
+ topK: 5,
+ });
向量儲存方法重新命名「向量儲存方法重新命名」的直接連結
updateIndexById 與 deleteIndexById 方法已分別重新命名為 updateVector 與 deleteVector。新名稱指出這些方法會對向量執行作業。
遷移時,請重新命名方法並傳入引數物件。
- await vectorDB.updateIndexById(indexName, id, update);
- await vectorDB.deleteIndexById(indexName, id);
+ await vectorDB.updateVector({ indexName, id, update });
+ await vectorDB.deleteVector({ indexName, id });
PGVector 建構函式從連線字串改為物件「PGVector 建構函式從連線字串改為物件」的直接連結
PGVector 建構函式現在必須使用物件參數,而非連線字串。這項變更讓所有儲存空間轉接器的 API 更一致。
遷移時,請將連線字串作為物件屬性傳入。
- const pgVector = new PgVector(process.env.POSTGRES_CONNECTION_STRING!);
+ const pgVector = new PgVector({
+ connectionString: process.env.POSTGRES_CONNECTION_STRING,
+ });
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/vector-pg-constructor .
PGVector 的 defineIndex 改為 buildIndex「pgvector-defineindex-to-buildindex」的直接連結
defineIndex() 方法已移除,請改用 buildIndex();新名稱指出此方法會建置索引。
遷移時,請重新命名方法並傳入引數物件。
- await vectorDB.defineIndex(indexName, 'cosine', { type: 'flat' });
+ await vectorDB.buildIndex({
+ indexName: indexName,
+ metric: 'cosine',
+ indexConfig: { type: 'flat' },
+ });
PostgresStore:schema 改為 schemaName「postgresstore-schema-to-schemaname」的直接連結
PostgresStore 建構函式中的 schema 參數已重新命名為 schemaName。新名稱指出此值是資料庫結構描述的名稱。
遷移時,請重新命名參數。
const pgStore = new PostgresStore({
connectionString: process.env.POSTGRES_CONNECTION_STRING,
- schema: customSchema,
+ schemaName: customSchema,
});
你可以使用 Mastra 的 codemod CLI 自動更新程式碼:
npx @mastra/codemod@latest v1/storage-postgres-schema-name .
分數儲存方法改為 listScoresBy* 模式「score-storage-methods-to-listscoresby-pattern」的直接連結
分數儲存 API 已重新命名,以遵循 listScoresBy* 模式。這項變更與更廣泛的 API 命名慣例保持一致。
遷移時,請將方法名稱從 getScores 更新為 listScoresByScorerId 及相關變體。
- const scores = await storage.getScores({ scorerName: 'helpfulness-scorer' });
+ const scores = await storage.listScoresByScorerId({
+ scorerId: 'helpfulness-scorer',
+ });
+ // Also available: listScoresByRunId, listScoresByEntityId, listScoresBySpan
已移除「已移除」的直接連結
非分頁儲存空間函式「非分頁儲存空間函式」的直接連結
非分頁儲存空間函式已移除,請改用分頁版本。所有 list 作業現在都使用分頁,但可以使用 perPage: false 擷取所有記錄。這項變更讓 API 保持一致,並避免意外載入大型資料集。
遷移時,請透過領域儲存空間使用分頁方法。若要擷取所有記錄,請使用 perPage: false。
- // Non-paginated direct access
- const messages = await storage.getMessages({ threadId });
+ // Use paginated methods via domain stores
+ const memoryStore = await storage.getStore('memory');
+ const result = await memoryStore?.listMessages({ threadId, page: 0, perPage: 20 });
+ // Or fetch all
+ const allMessages = await memoryStore?.listMessages({
+ threadId,
+ page: 0,
+ perPage: false,
+ });
getTraces 與 getTracesPaginated「gettraces-and-gettracespaginated」的直接連結
儲存空間已移除 getTraces() 與 getTracesPaginated() 方法。請透過可觀測性套件存取 Trace,而非核心儲存空間。
遷移時,請改用可觀測性儲存方法。
- const traces = await storage.getTraces({ traceId: 'trace-123' });
- const paginated = await storage.getTracesPaginated({ page: 0, perPage: 20 });
+ // Use observability API for traces
+ import { initObservability } from '@mastra/observability';
+ const observability = initObservability({ config: { ... } });
+ // Access traces through observability API
Evals 測試公用程式「Evals 測試公用程式」的直接連結
@internal/test-utils 已移除 Evals 領域測試公用程式。這項變更反映舊版 Evals 功能已移除。
遷移時,請直接使用儲存空間 API 進行測試,而非專用的 Evals 測試公用程式。
- import { createEvalsTests } from '@internal/test-utils/domains/evals';
- createEvalsTests({ storage });
+ // Use storage APIs directly for testing
MSSQL 儲存空間中的 TABLE_EVALS「MSSQL 儲存空間中的 TABLE_EVALS」的直接連結
MSSQL 儲存空間實作已移除 TABLE_EVALS 資料表。這項變更反映舊版 Evals 功能已移除。
如果原本使用 MSSQL 儲存空間搭配 Evals,請遷移至其他儲存空間轉接器,或移除 Evals 功能。