.agents/design/common/mongo-index-sync-strategy.md
pro/admin 中由 FastGPT 管理的 MongoDB Schema私有化部署客户可能通过 mongosh、运维脚本或数据库管理平台添加自定义索引。原实现会在 Mongoose model 加载时调用 model.syncIndexes(),其语义是:
因此,客户自建索引在服务重启时被删除是 syncIndexes() 的确定性行为,并非异常分支。原有 SYNC_INDEX=false 虽然可以阻止删除,但也会阻止 FastGPT 新版本补建必需索引,无法作为默认解决方案。
该问题同时影响主业务库、日志库和 Marketplace;多实例启动还会放大重复执行和错误日志问题。
syncIndexes() 或 cleanIndexes()。SYNC_INDEX 弃用;启动时固定检查差异并补建当前 Schema 缺失的索引。MONGO_DEPRECATE_INDEX 仅控制是否清理显式声明的 FastGPT 系统内置废弃索引,默认值为 true;设置为 false 不影响缺失索引的创建。defineIndex() 声明;废弃索引必须声明在所属 Schema 文件中。MongoIndexManager,保持同步语义与错误处理一致。packages/service/common/mongo/schemaIndexes.ts 提供统一入口:
defineIndex(ChatSchema, {
key: { appId: 1, chatId: 1 },
options: { unique: true }
});
defineIndex(ChatSchema, {
key: { legacyField: 1 },
options: { name: 'legacyField_1' },
deprecated: true
});
声明规则:
deprecated 时,defineIndex() 代理 Schema.index(),该索引属于当前 Schema。deprecated: true 时,只在 Schema 实例上登记清理元数据,不再把索引加入 Mongoose Schema。index: true 或 unique: true 隐式声明,避免绕开统一入口。废弃索引元数据使用私有 symbol 挂在 Schema 实例上,使当前索引与历史清理声明在同一业务文件中完成 review,并避免中心清单与 Schema 演进脱节。
每个 model 启动时执行以下流程:
diffIndexes({ indexOptionsToCreate: true }) 生成 toCreate 和 toDrop。toDrop 仅表示数据库中存在但当前 Schema 未声明的索引,记录 warn 后保留。createIndexes({ background: true }) 创建当前 Schema 索引。MONGO_DEPRECATE_INDEX=true 时,从 model.schema 读取废弃索引声明。key 匹配规则:
listIndexes 的 key 与声明 key 按字段顺序精确相等。{ _fts: "text", _ftsx: 1 },因此改为比较声明中的 text 字段集合与 weights 字段集合。unique / sparse / TTL / partial / collation)故意不参与匹配,减少重复声明成本;声明方需自行确认同名同 key 的索引确实可删。清理结果分为:
drop:定义匹配,已删除或在 dry-run 中可删除。skip_missing:索引不存在或已被其他实例删除。skip_mismatch:同名索引的 key 不匹配,保留并告警。error:查询或删除失败,保留错误信息。同一进程内同一 model 的并发调用复用正在执行的任务;任务完成后移除缓存,允许热加载或重连再次检查。多实例重复清理时,IndexNotFound 视为幂等跳过。
packages/service/common/mongo/indexManager.ts
inspectModelIndexes():只计算差异,不创建或删除索引。syncModelIndexes():执行安全同步并复用同一 model 的进行中任务。cleanupModelDeprecatedIndexes():按 Schema 本地声明检查或清理废弃索引。summarizeCleanupReport() / formatCleanupReport():提供结构化结果与可读报告。packages/service/common/mongo/schemaIndexes.ts
defineIndex():声明当前索引或登记废弃索引。getDeprecatedIndexes():读取当前 Schema 自身的废弃索引元数据。packages/service/common/mongo/index.ts
projects/marketplace/src/service/mongo/index.ts
原中心废弃索引清单已删除。当前 chat、sandbox instance 和 Agent Skill 均未登记废弃索引,因此启动同步不会自动删除任何历史索引;manager 仅保留显式清理能力供后续经过单独确认的迁移使用。
info:实际创建或删除索引时输出 collection 级摘要。warn:发现 Schema 外索引,或废弃声明与数据库同名索引不匹配。error:当前索引创建失败,或废弃索引检查、删除失败。索引任务失败不阻止 model 注册,但必须记录 model、collection 和错误信息。createIndexes() 的同名、同 key 或 options 冲突由 MongoDB/Mongoose 抛错并进入错误日志,不自动修正。
createIndexes() 不会修改已存在索引的 options。TTL、唯一约束、partial filter 等变化必须通过明确迁移处理。MONGO_DEPRECATE_INDEX=false 只关闭废弃索引清理,当前 Schema 缺失的索引仍会创建。llm_request_records.requestId_176d6234de V4.14.7 features (#6406) 首次在 requestId path 上声明 unique: true,MongoDB 创建 requestId_1。f008ea971 feat: teamId in reacord llm 将约束调整为 { teamId: 1, requestId: 1 } 复合唯一索引。packages/service/core/ai/record/schema.ts 单独声明并补充回归测试。MONGO_DEPRECATE_INDEX 统一控制废弃索引清理。以下事项不影响当前方案交付:
llm_request_records.requestId_1。fg_<collection>_<purpose> 显式命名规范;旧索引不做批量改名。