在使用Go语言操作MongoDB时,mgo驱动是实现数据读写、备份恢复的常用工具。当需要从已有的备份文件中恢复数据时,我们可以根据备份文件的格式选择BSON或者JSON两种导入策略,两种策略的实现逻辑和适用场景存在明显差异。

BSON与JSON备份格式的特点对比
在选择导入策略前,我们需要先了解两种备份格式的核心差异,具体对比如下:
| 对比维度 | BSON格式 | JSON格式 |
|---|---|---|
| 存储体积 | 更小,二进制编码无冗余 | 更大,文本格式包含额外字符 |
| 数据类型支持 | 完整支持MongoDB所有数据类型 | 部分特殊类型需要额外转换 |
| 可读性 | 不可直接阅读 | 可直接阅读和编辑 |
| 导入效率 | 更高,无需解析文本 | 更低,需要文本解析转换 |
BSON格式备份导入策略
BSON是MongoDB原生的数据存储格式,使用mgo导入BSON备份时,我们可以直接读取二进制数据并写入集合,不需要额外的格式转换,效率更高。
实现步骤
- 打开BSON备份文件,读取二进制数据
- 建立MongoDB连接,获取目标集合的会话
- 将BSON数据解析为文档结构,批量插入集合
代码示例
以下是基于mgo导入BSON备份的完整实现:
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"os"
"log"
)
func importBSONBackup(mongoURL string, dbName string, collName string, bsonFilePath string) error {
// 建立MongoDB连接
session, err := mgo.Dial(mongoURL)
if err != nil {
return err
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
// 获取目标集合
coll := session.DB(dbName).C(collName)
// 读取BSON备份文件
fileData, err := os.ReadFile(bsonFilePath)
if err != nil {
return err
}
// 解析BSON数据,假设备份是单个文档,如果是多个文档需要循环解析
var doc bson.M
err = bson.Unmarshal(fileData, &doc)
if err != nil {
return err
}
// 插入文档
err = coll.Insert(doc)
if err != nil {
return err
}
log.Println("BSON备份导入成功")
return nil
}
func main() {
// 示例调用,连接本地MongoDB,导入test库的user集合的BSON备份
err := importBSONBackup("127.0.0.1:27017", "test", "user", "./user_backup.bson")
if err != nil {
log.Fatalf("导入失败: %v", err)
}
}
JSON格式备份导入策略
JSON格式的备份可读性更强,适合需要手动修改备份内容的场景,但导入时需要将JSON文本转换为MongoDB支持的文档结构,部分特殊类型需要额外处理。
实现步骤
- 读取JSON备份文件内容
- 将JSON字符串解析为Go的map结构
- 处理JSON中无法直接表示的MongoDB特殊类型,比如ObjectId、日期等
- 批量插入到目标集合
代码示例
以下是基于mgo导入JSON备份的实现,包含特殊类型的处理逻辑:
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"encoding/json"
"os"
"log"
"time"
)
// 自定义JSON解析结构,处理日期类型
type BackupDoc struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"_id"`
Name string `bson:"name" json:"name"`
Age int `bson:"age" json:"age"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
}
func importJSONBackup(mongoURL string, dbName string, collName string, jsonFilePath string) error {
// 建立MongoDB连接
session, err := mgo.Dial(mongoURL)
if err != nil {
return err
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
// 获取目标集合
coll := session.DB(dbName).C(collName)
// 读取JSON备份文件
fileData, err := os.ReadFile(jsonFilePath)
if err != nil {
return err
}
// 解析JSON数据
var doc BackupDoc
err = json.Unmarshal(fileData, &doc)
if err != nil {
return err
}
// 如果JSON中的_id是字符串,转换为bson.ObjectId
if doc.ID == "" {
doc.ID = bson.NewObjectId()
}
// 插入文档
err = coll.Insert(doc)
if err != nil {
return err
}
log.Println("JSON备份导入成功")
return nil
}
func main() {
// 示例调用,导入test库的user集合的JSON备份
err := importJSONBackup("127.0.0.1:27017", "test", "user", "./user_backup.json")
if err != nil {
log.Fatalf("导入失败: %v", err)
}
}
两种策略的选择建议
在实际使用中,我们可以根据场景选择对应的策略:
- 如果是全量备份恢复,不需要修改备份内容,优先选择BSON策略,导入效率更高,也不会出现类型丢失问题
- 如果备份需要人工审核、修改部分字段,或者备份文件需要跨系统传输,优先选择JSON策略,可读性更强
- 如果备份中包含大量二进制数据、特殊日期类型,建议使用BSON策略,避免JSON转换时的类型错误
注意事项
使用mgo导入备份时需要注意以下几点:
- 导入前确认目标集合的索引情况,避免重复插入导致索引冲突
- 大文件备份建议分批次导入,避免单次插入数据量过大导致内存溢出
- 生产环境导入前建议先在测试环境验证备份文件的完整性和兼容性
- 如果MongoDB开启了权限认证,连接时需要添加对应的账号密码信息
注意:mgo驱动目前已经停止维护,新项目建议使用官方Go驱动go.mongodb.org/mongo-driver,导入逻辑类似,只需要调整对应的API调用即可。