Go批量操作excel导入到mongodb的技巧
怎么入门Golang编程?需要学习哪些知识点?这是新手们刚接触编程时常见的问题;下面golang学习网就来给大家整理分享一些知识点,希望能够给初学者一些帮助。本篇文章就来介绍《Go批量操作excel导入到mongodb的技巧》,涉及到Excel、导入、mongo,有需要的可以收藏一下
需求:完成一个命令工具,批量处理某个目录下面的一些excel,将这些excel数据导入到mongodb,同时可以同步到mysql
:: 花了一天时间写完代码,代码库位置:https://gitee.com/foz/lib/tree/master/ecc
代码目录:
├─cmd | └─ecc.go # 命令 ├─configs ├─data ├─internal │ └─importing # 主要逻辑处理 ├─pkg # 处理文件读取、连接数据库等 │ ├─files │ ├─mongo │ └─mysql ├─queue └─tools
1. 选择命令行包
平常使用的的命令工具包有:
- urfave/cli
- spf13/cobra
这里使用的是urfave/cli包,比较简单
var DirPath = "../data" // 默认位置
var dir = DirPath
app := &cli.App{
Name: "Ecc",
Usage: "Ecc is a tools for batch processing of excel data",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "model",
Aliases: []string{"m"},
Usage: "The model of searching",
Value: "model",
Destination: &model,
},
&cli.StringFlag{ // 设置一个 -d 的参数,用来确定目标文件夹位置
Name: "dir",
Aliases: []string{"d"},
Usage: "Folder location of data files",
Destination: &dir,
Value: DirPath,
},
Action: func(c *cli.Context) error {
importing.Load("../configs/cfg.yaml") // 引入配置文件,读取mongodb、mysql等配置
importing.Handle(dir) ## 具体逻辑处理
return nil
}
2. 读取配置,连接数据库
读取配置使用spf13/viper库,需要读取一下配置,连接mongodb
var C Config
type Config struct {
Env string `yaml:"env"`
Mongo struct {
DNS string `yaml:"dns"`
Db string `yaml:"db"`
Collection string `yaml:"collection"`
} `yaml:"mongo"`
Mysql struct {
Alias string `yaml:"alias"`
Dns string `yaml:"dns"`
} `yaml:"mysql"`
}
func Load(cf string) {
var err error
viper.SetConfigFile(cf)
if err = viper.ReadInConfig(); err != nil {
log.Fatal(fmt.Errorf("fatal error config file: %s \n", err))
}
if err = viper.Unmarshal(&configs.C); err != nil {
log.Fatal(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
if err = mongo.Conn(configs.C.Mongo.DNS, configs.C.Mongo.Db); err != nil {
log.Fatal(color.RedString("%s:\n%v", "mongo connect err", err))
if mongo.CheckCollection(configs.C.Mongo.Collection) {
if err = mongo.DelCollection(configs.C.Mongo.Collection); err != nil {
log.Fatal(color.RedString("%s:\n%v", "mongo del collection err", err))
}
if err = mongo.CreateCollection(configs.C.Mongo.Collection); err != nil {
log.Fatal(color.RedString("%s:\n%v", "mongo create collection err", err))
3. 读取文件
先确定文件权限以及文件是否存在
func ReadDir(dir string) ([]os.FileInfo, error) {
perm := checkPermission(dir)
if perm == true {
return nil, fmt.Errorf("permission denied dir: %s", dir)
}
if isNotExistDir(dir) {
return nil, fmt.Errorf("does not exist dir: %s", dir)
files, err := ioutil.ReadDir(dir)
if err == nil {
return files, err
return nil, fmt.Errorf("ReadDir: %s, err: %v", dir, err)
}
拿到文件后就要并发读取每个excel文件数据
这里需求是一次任务必须读完所有的文件,任何一个文件有错误就退出程序。
:: 所以需要定义异常退出信道和一个完成读取两个信道,总的数据使用sync.Map安全并发写入。
3.1. 并发读
rWait = true
rDone = make(chan struct{})
rCrash = make(chan struct{})
read(f, dir, data)
for rWait { // 使用for循环来阻塞读文件
select {
case Failure")
return
case
3.2. 使用excelize处理excel
excelize是一个非常好用的excel处理库,这里使用这个库读取excel文件内容
type ExcelPre struct {
FileName string
Data [][]string
Fields []string
Prefixes string
ProgressBar *mpb.Bar // 进度条对象
}
func ReadExcel(filePath, fileName string, pb *mpb.Progress) (err error, pre *ExcelPre) {
f, err := excelize.OpenFile(filePath)
if err != nil {
return err, nil
}
defer func() {
if _e := f.Close(); _e != nil {
fmt.Printf("%s: %v.\n\n", filePath, _e)
}
}()
// 获取第一页数据
firstSheet := f.WorkBook.Sheets.Sheet[0].Name
rows, err := f.GetRows(firstSheet)
lRows := len(rows)
if lRows
3.3. 使用mpb在命令行输出进度显示
mpb是一个很好用的命令行进度输出库,上面代码里里有两个进度条,一个是读进度条,第二个是写进度条,读进度条在文件读取的时候就显示了,返回的结构体里有写进度条对象,便于后面写操作时候显示。
下面是两个进度条显示的配置,具体参数可以看这个库的文档。
func ReadBar(total int, name string, pb *mpb.Progress) *mpb.Bar {
return pb.AddBar(int64(total),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(color.YellowString("reading"), decor.WCSyncSpaceR), color.YellowString("waiting")),
decor.CountersNoUnit("%d / %d", decor.WCSyncWidth, decor.WCSyncSpaceR),
),
mpb.AppendDecorators(
decor.NewPercentage("%.2f:", decor.WCSyncSpaceR),
decor.EwmaETA(decor.ET_STYLE_MMSS, 0, decor.WCSyncWidth),
decor.Name(": "+name),
)
}
func WriteBar(total int, name string, beforeBar *mpb.Bar, pb *mpb.Progress) *mpb.Bar {
mpb.BarQueueAfter(beforeBar, false),
mpb.BarFillerClearOnComplete(),
decor.OnComplete(decor.Name(color.YellowString("writing"), decor.WCSyncSpaceR), color.GreenString("done")),
decor.OnComplete(decor.CountersNoUnit("%d / %d", decor.WCSyncSpaceR), ""),
decor.OnComplete(decor.NewPercentage("%.2f:", decor.WCSyncSpaceR), ""),
decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_MMSS, 0, decor.WCSyncWidth), ""),
decor.OnComplete(decor.Name(": "+name), name),
4. 写入mongodb
同写入操作,这里拿到所有数据,然后使用goroutine并发写入mongodb,在处理数据时候需要查重,还需要记录一下本次操作插入了哪些数据的_id值,在报错的时候进行删除(这里可以使用事务,直接删除简单些),所以定义了一个Shuttle结构体用来在记录并发时的数据。
wWait = true
wDone = make(chan struct{})
wCrash = make(chan struct{})
type Shuttle struct {
Hid []string // 用来判断是否是重复数据
Mid []string // 用来记录本次插入的数据_id
mu sync.Mutex
}
func (s *Shuttle) Append(t string, str string) {
s.mu.Lock()
defer s.mu.Unlock()
switch t {
case "h":
s.Hid = append(s.Hid, str)
case "m":
s.Mid = append(s.Mid, str)
}
write2mongo(data)
for wWait {
select {
case Failure")
return
case
5. 同步mysql
因为同步mysql不是必要的,这里使用命令行输入进行判断:
tools.Yellow("-> Whether to sync data to mysql? (y/n)")
if !tools.Scan("aborted") {
return
} else {
tools.Yellow("-> Syncing data to mysql...")
if err = write2mysql(); err != nil {
tools.Red("-> Failure:" + err.Error())
} else {
tools.Green("-> Success.")
}
}
连接mysql数据库,拿到当前monogodb的数据:
func write2mysql() error {
if err := mysql.Conn(configs.C.Mysql.Dns); err != nil {
return err
}
d, err := mongo.GetCollectionAllData(configs.C.Mongo.Collection)
if err != nil {
err = Write2Mysql(d)
return err
}
创建表,直接拼sql就完事了:
func CreateTable(tableName string, fields []string) error {
var err error
delSql := fmt.Sprintf("DROP TABLE IF EXISTS `%s`", tableName)
err = Db.Exec(delSql).Error
if err != nil {
return err
}
s := "id bigint(20) NOT NULL PRIMARY KEY"
for _, field := range fields {
s += fmt.Sprintf(",%s varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL", field)
sql := fmt.Sprintf("CREATE TABLE `%s` (%s) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", tableName, s)
err = Db.Exec(sql).Error
return nil
}
插入数据,bson.M本身就是一个map,转一下使用gorm分批插入数据,速度快一点:
func InsertData(tableName string, fields []string, data []bson.M) error {
var err error
var maps []map[string]interface{}
for _, d := range data {
row := make(map[string]interface{})
for _, field := range fields {
row[field] = d[field]
}
if row != nil {
row["id"] = d["id"].(string)
maps = append(maps, row)
}
if len(maps) > 0 {
err = Db.Table(tableName).CreateInBatches(maps, 100).Error
if err != nil {
return err
return err
}
6. 总结
做为golang新手,看了很多文档、文章,好似懂了,其实啥都不懂。
理论要掌握,实操不能落!以上关于《Go批量操作excel导入到mongodb的技巧》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
go语言实现两个协程交替打印
- 上一篇
- go语言实现两个协程交替打印
- 下一篇
- 从零开始学Golang的接口
-
- 内向的斑马
- 这篇文章内容真及时,很详细,很棒,已加入收藏夹了,关注老哥了!希望老哥能多写Golang相关的文章。
- 2023-02-12 05:32:29
-
- 大力的柚子
- 这篇博文太及时了,太详细了,感谢大佬分享,码起来,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-02-04 17:37:41
-
- 淡定的缘分
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢老哥分享技术贴!
- 2023-01-31 09:47:26
-
- 悲凉的人生
- 这篇技术贴出现的刚刚好,楼主加油!
- 2023-01-02 22:54:21
-
- 洁净的可乐
- 太详细了,收藏了,感谢up主的这篇技术贴,我会继续支持!
- 2022-12-29 08:33:54
-
- 傻傻的玫瑰
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢大佬分享文章!
- 2022-12-26 06:32:21
-
- 心灵美的小懒虫
- 这篇技术文章太及时了,太全面了,受益颇多,已收藏,关注老哥了!希望老哥能多写Golang相关的文章。
- 2022-12-24 07:42:38
-
- Golang · Go教程 | 20小时前 | 并发 · Go教程 · trace.NewTask go tool trace Go runtime/trace 执行跟踪 trace.WithRegion
- Go runtime/trace 怎样按任务标记跟踪区间
- 391浏览 收藏
-
- Golang · Go教程 | 20小时前 | flag · go · Go 命令行参数 flag.TextVar encoding.TextUnmarshaler
- Go flag.TextVar 怎样把自定义类型接入命令行
- 184浏览 收藏
-
- Golang · Go教程 | 22小时前 | 错误处理 · 模板 · Go教程 · html/template · 模板渲染 Go html/template missingkey 模板缺失字段 Execute错误
- Go html/template 缺失字段的严格渲染配置与错误处理
- 371浏览 收藏
-
- Golang · Go教程 | 22小时前 | html · go · 模板 · url · Go html/template 自动转义 URL上下文 template.URL
- Go html/template 怎样避免 URL 上下文误用
- 326浏览 收藏
-
- Golang · Go教程 | 22小时前 |
- Go text/template.ParseFS 怎样加载嵌入文件模板
- 208浏览 收藏
-
- Golang · Go教程 | 22小时前 |
- Go database/sql.NamedArg 怎样给 SQL 参数命名
- 311浏览 收藏
-
- Golang · Go教程 | 22小时前 | HTTP · go · Gin · Gin ShouldBindBodyWith 请求体重复绑定 ShouldBind binding.JSON
- Gin ShouldBindBodyWith 怎么让同一个请求体绑定两次
- 134浏览 收藏
-
- Golang · Go教程 | 23小时前 | go · 文件系统 · Go os.ReadDir Go File.ReadDir Go DirEntry Go 目录遍历
- Go os.ReadDir 怎样高效读取目录条目
- 269浏览 收藏
-
- Golang · Go教程 | 23小时前 | go · Go go/types.Config Go Importer Go 类型检查 types.Check
- Go go/types.Config 怎样给类型检查接入导入器
- 222浏览 收藏
-
- Golang · Go教程 | 23小时前 |
- Go maphash.Hash 怎样用固定种子复现哈希结果
- 341浏览 收藏
-
- Golang · Go教程 | 23小时前 | Go 字节切片 encoding/binary AppendByteOrder
- Go binary.ByteOrder.Append 怎样把整数追加到现有字节切片
- 373浏览 收藏
-
- Golang · Go教程 | 1天前 | go · IPv6 Go ipv4 netip.ParsePrefix CIDR
- Go netip.ParsePrefix 怎样解析 CIDR 字符串
- 334浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 574次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 616次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 647次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 607次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 423次使用
-
- 服装入库台账怎么用 Excel 数据验证做尺码下拉:限制录入与错误提示
- 2026-08-30 444浏览
-
- GoJava算法之Excel表列名称示例详解
- 2023-01-23 190浏览
-
- Go结合Gin导出Mysql数据到Excel表格
- 2023-01-01 352浏览
-
- golang实现浏览器导出excel文件功能
- 2022-12-31 224浏览
-
- 手把手教你导入Go语言第三方库
- 2023-01-01 312浏览

