Golang mongodb使用

Stella981
• 阅读 751

资料

官方文档

官方驱动github

之前一直使用mgo,但是已经不维护了,(mgo:是MongoDB的Go语言驱动,它用基于Go语法的简单API实现了丰富的特性,并经过良好测试。使用起来很顺手,文档足够),因此转到mongodb官方driver。mongo-go-driver:官方的驱动,设计的很底层,因此扩展性比较好,但是使用复杂度有一定提高,并且支持事务。

入门

连接
import (
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))

go的连接驱动一般都支持连接池,果不其然,mongodb也是,我们查看源码发现可以设置

options对象里包含连接池大小配置,可以方便开发根据环境进行配置。

MaxPoolSize            *uint64
MinPoolSize            *uint64
查询

查询相对复杂,会返回一个迭代器,这时候可以封装一个共用方法进行处理

ctx, _ = context.WithTimeout(context.Background(), 30*time.Second)
cur, err := collection.Find(ctx, bson.D{})
if err != nil { log.Fatal(err) }
defer cur.Close(ctx)
for cur.Next(ctx) {
   var result bson.M
   err := cur.Decode(&result)
   if err != nil { log.Fatal(err) }
   // do something with result....
}
if err := cur.Err(); err != nil {
  log.Fatal(err)
}
插入

没啥难度,和其他db差不多

collection := client.Database("testing").Collection("pi_test")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
 _, err := collection.InsertOne(ctx, bson.M{"name": "pi", "value": math.Round(10000)})
更新
    c := Connect(db, collection)
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    opts := options.Update().SetUpsert(true)
    _, err := c.UpdateOne(ctx, query, update,opts)

mongo-go-driver需要设置opts := options.Update().SetUpsert(true),如果是想要进行upsert

删除
    c := Connect(db, collection)
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    _, err :=collection.DeleteOne(ctx, bson.M{"name": "pi", "value": math.Round(10000)})
事务的支持

MongoDB 4.0 引入的事务功能,支持多文档ACID特性,这实在是一件棒棒哒的事情(nosql事务哟)

只有官方驱动才支持事务,mgo已经年久失修了,别用了,放弃吧!

因为多处使用,所以封装了一个方法(此处封装来自于mgo vs mongodb driver); 在这个方法中需要实现的方法是Exec的operator

type DBTransaction struct {
    Commit func(mongo.SessionContext) error
    Run    func(mongo.SessionContext, func(mongo.SessionContext, DBTransaction) error) error
    Logger *logging.Logger
}

func NewDBTransaction(logger *logging.Logger) *DBTransaction {
    var dbTransaction = &DBTransaction{}
    dbTransaction.SetLogger(logger)
    dbTransaction.SetRun()
    dbTransaction.SetCommit()
    return dbTransaction
}

func (d *DBTransaction) SetCommit() {
    d.Commit = func(sctx mongo.SessionContext) error {
        err := sctx.CommitTransaction(sctx)
        switch e := err.(type) {
        case nil:
            d.Logger.Info("Transaction committed.")
            return nil
        default:
            d.Logger.Error("Error during commit...")
            return e
        }
    }
}

func (d *DBTransaction) SetRun() {
    d.Run = func(sctx mongo.SessionContext, txnFn func(mongo.SessionContext, DBTransaction) error) error {
        err := txnFn(sctx, *d) // Performs transaction.
        if err == nil {
            return nil
        }
        d.Logger.Error("Transaction aborted. Caught exception during transaction.",
            zap.String("error", err.Error()))

        return err
    }
}

func (d *DBTransaction) SetLogger(logger *logging.Logger) {
    d.Logger = logger
}

func (d *DBTransaction) Exec(mongoClient *mongo.Client, operator func(mongo.SessionContext, DBTransaction) error) error {
    ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute)
    defer cancel()

    return mongoClient.UseSessionWithOptions(
        ctx, options.Session().SetDefaultReadPreference(readpref.Primary()),
        func(sctx mongo.SessionContext) error {
            return d.Run(sctx, operator)
        },
    )
}

//具体调用
func SyncBlockData(node models.DBNode) error {
    dbTransaction := db_session_service.NewDBTransaction(Logger)

    // Updates two collections in a transaction.
    updateEmployeeInfo := func(sctx mongo.SessionContext, d db_session_service.DBTransaction) error {
        err := sctx.StartTransaction(options.Transaction().
            SetReadConcern(readconcern.Snapshot()).
            SetWriteConcern(writeconcern.New(writeconcern.WMajority())),
        )
        if err != nil {
            return err
        }
        err = models.InsertNodeWithSession(sctx, node)
        if err != nil {
            _ = sctx.AbortTransaction(sctx)
            d.Logger.Info("caught exception during transaction, aborting.")
            return err
        }

        return d.Commit(sctx)
    }

    return dbTransaction.Exec(models.DB.Mongo, updateEmployeeInfo)
}

总结

就是一篇记录常用api的记录,顺便记录下遇到的坑。

ps:官方测试总是吧 context的 退出给关闭了。 Golang mongodb使用

实际上应该合理处理

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() //一定记得加defer
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这