mongodump和mongorestore不能开箱即用迁移gridfs数据,必须显式导出fs.files与fs.chunks、保持相同--out路径、还原时使用--drop并指定db子目录路径,否则必丢文件或报filenotfound。

直接说结论:mongodump 和 mongorestore 不能“开箱即用”迁移 GridFS 数据——默认会跳过 fs.files 和 fs.chunks,导致还原后文件全部丢失。必须显式指定集合、控制顺序、加 --drop,否则必出 FileNotFound 错误。
为什么 mongodump 默认不导出 fs.files 和 fs.chunks
GridFS 不是单个集合,而是由 fs.files(元数据)和 fs.chunks(二进制块)两个强关联集合构成。mongodump 默认只 dump 用户创建的「顶层集合」,把 fs.* 当作内部命名空间过滤掉了。
- 执行
mongodump --db myapp后检查 dump 目录,你会发现根本没有fs.files.bson或fs.chunks.bson -
--collections参数不支持通配符或前缀匹配,--collections fs.*会报错 - 即使你只导出
fs.files,mongorestore也无法自动补全对应fs.chunks,因为 chunk 的files_id字段不会被校验或修复
正确导出:必须分两步,且路径严格一致
导出不是“选一个命令敲一下”,而是两个独立但强耦合的 mongodump 命令,且输出路径必须完全相同,否则 mongorestore 无法识别它们属于同一逻辑单元。
- 先执行:
mongodump --db myapp --collection fs.files --out /backup/gridfs/ - 再执行:
mongodump --db myapp --collection fs.chunks --out /backup/gridfs/ -
--out路径必须一致,最终生成的是/backup/gridfs/myapp/fs.files.bson和/backup/gridfs/myapp/fs.chunks.bson - 如果业务写入活跃,建议停写或加读锁,否则可能因
chunks写入未完成,导致还原后文件内容损坏
正确还原:必须用 --drop,且 restore 整个 db 子目录
mongorestore 对 GridFS 最危险的误操作,就是单独 restore 某个集合,或者漏掉 --drop。
- 绝对不要用:
mongorestore --collection fs.files ...—— 这会破坏fs.files._id与fs.chunks.files_id的索引一致性 - 必须用:
mongorestore --drop --db myapp /backup/gridfs/myapp/(注意路径末尾是myapp/,不是gridfs/) -
--drop是必须的:目标库若已有fs.files或fs.chunks,重复插入会触发E11000 duplicate key错误;清空集合(deleteMany)也可行,但容易漏掉索引或权限问题 - 还原后立刻验证:不能只查集合是否存在,要用
GridFSBucket.find().toArray()看能否列出文件,再挑一个调用openDownloadStream测试能否读取内容
最容易被忽略的三个细节
迁完发现文件打不开,90% 都栽在这三点上:
-
mongorestore的路径指向错误:写成/backup/gridfs/(上层目录)而不是/backup/gridfs/myapp/(db 子目录),会导致它找不到任何 bson 文件 - 没确认旧库和新库的 GridFS 前缀是否一致:默认是
fs,但应用可能用了uploads或media,导出时得换成--collection uploads.files - 还原后没清理孤立 chunk:上传中断遗留的
fs.chunks文档(files_id指向不存在的fs.files._id)会持续占磁盘,需定期运行db.fs.chunks.deleteMany({ files_id: { $nin: db.fs.files.distinct("_id") } })











