当前位置: 首页 > 工具软件 > GO daemon > 使用案例 >

mongo-go-driver使用简介

华子航
2023-12-01

1. mongo-go-driver包的导入或安装

对于使用go modules来进行包管理的开发人员,可以通过从go.mongodb.org/mongo-driver导入包并让构建步骤来自动安装依赖包,或者通过显式运行以下命令来安装:

go get go.mongodb.org/mongo-driver/mongo

如果你使用的是不支持modules的go版本,你可以使用dep来安装:

dep ensure -add "go.mongodb.org/mongo-driver/mongo"

2.MongoDB数据库连接的初始化和关闭

正常情况下,我们需要保存一个连接到MongoDB的client一段时间,以便应用程序可以利用连接池。这样就不会你每次操作都需要执行一次打开和关闭连接的操作。为了能够实现对连接的复用,我在程序中首先声明了一个MongoConn的结构体,此结构体用来存储MongoDB连接相关的信息,具体如下:

type MongoConn struct {
    clientOptions *options.ClientOptions
    client        *mongo.Client
    collections   *mongo.Collection
}
var mongoConn *MongoConn

下面的函数InitMongoConn,用来初始化到MongoDB数据库的连接,主要有以下几个步骤:
1)构建context
2)配置client option
3)连接MongoDB数据库
4)检查连接是否有效
5)选择数据库dbname中的集合tests

func InitMongoConn(url, user, password, dbname string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Set client options
    // construct url: mongodb://username:password@127.0.0.1:27017/dbname
    mongoUrl := "mongodb://" + user + ":" + password + "@" + url + "/" + dbname
    mongoConn.clientOptions := options.Client().ApplyURI(mongoUrl)

    // Connect to MongoDB
    var err error
    mongoConn.client, err := mongo.Connect(ctx, mongoConn.clientOptions)
    if err != nil {
        klog.Fatalf("connect to mongodb error: %v", err)
    }

    // Check the connection
    err = mongoConn.client.Ping(context.TODO(), nil)
    if err != nil {
        klog.Fatalf("check the connection to mongo error: %v", err)
    }

    collections = mongoConn.client.Database(dbname).Collection("tests")
}

如果你的应用程序不再需要一个连接,我们可以调用以下方法关闭该连接:

func CloseMongoConn() {
    err := mongoConn.client.Disconnect(context.TODO())
    if err != nil {
        klog.Fatalf("disconnect mongo connect is error: %v", err)
        return
    }
    klog.Infof("connection to MongoDB closed.")
}

3.操作示例

当程序完成了MongoDB的连接之后,我们就要开始对数据库进行增删改查操作了.

3.1 插入操作

插入一条记录(其中,data为我们要插入到MongoDB中的数据):

	// insert data into database
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	insertResult, err := mongoConn.collections.InsertOne(ctx, data)
	if err != nil {
    	klog.Errorf("err: %s", err)
	}
	klog.Infof("Inserted a single document: ", insertResult.InsertedID)

插入多条记录(其中,datas为我们要插入到MongoDB中的多条数据的切片数组):

	// insert datas into database
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	insertManyResult, err := mongoConn.collections.InsertMany(ctx, datas)
	if err != nil {
    	klog.Errorf("err: %s", err)
	}
	klog.Infof("successfully inserted multiple documents: ", insertManyResult.InsertedIDs)

3.2 查询操作

查询多条记录, 使用collection.Find(),这个函数返回一个游标。
返回的游标提供一个文档流, 通过它你可以遍历和解码每一个文档。一旦一个游标被消耗掉, 你应该关闭游标。
这里你也可以使用options包来设定一些操作选项, 特别的, 你可以设定一个返回文档数量的限制, 比如5个。

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	filter := bson.D{}

	findOptions := options.Find()
	findOptions.SetLimit(5)

	cur, err := mongoConn.collections.Find(ctx, filter, findOptions)
	if err != nil {
    	klog.Fatal(err)
	}

	// Close the cursor once finished
	defer cur.Close(context.TODO())

3.3 分页查询

当集合中存储了大量的数据后,一般情况下我们需要实现分页查询的功能,我们可以通过设置options的SetLimit和SetSkip来实现。
以下程序查询第5页,每页显示20条记录:

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	filter := bson.D{}

	// 分页查询选项设置
	// Pass these options to the Find method
	findOptions := options.Find()
	// use setlimit and setskip to implement pageable query
	findOptions.SetLimit(20)
	// specifies the number of documents to skip before returning.
	findOptions.SetSkip(20 * (5 - 1))

	cur, err := mongoConn.collections.Find(ctx, filter, findOptions)
	if err != nil {
   		klog.Fatal(err)
	}

	// Close the cursor once finished
	defer cur.Close(context.TODO())

3.4 删除操作

以下代码可以删除tests集合中的所有数据,如果要删除一些特定的数据的话,需要根据情况配置filter。

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	filter := bson.D{}
	deleteResult, err := mongoConn.collections.DeleteMany(ctx, filter)
	if err != nil {
    	log.Fatal(err)
	}
	klog.Fatalf("Deleted %v documents in the tests collection\n", deleteResult.DeletedCount)

也可以使用以下语句删除tests集合当中的所有数据:

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	mongoConn.collections.Drop(ctx)

4 bson简介

BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和BinData类型。
MongoDB使用了BSON这种结构来存储数据和网络数据交换。把这种格式转化成一文档这个概念(Document),因为BSON是schema-free的,所以在MongoDB中所对应的文档也有这个特征,这里的一个Document也可以理解成关系数据库中的一条记录(Record),只是这里的Document的变化更丰富一些,如Document可以嵌套。

4.1 bson的使用

在我们使用mongo-go-driver的过程中,我们会在查询,更新,删除记录的过程中使用到filter,即过滤条件。而mongo-go-driver中的filter是bson格式的,如下所示:

filter := bson.D{{"name", "Ash"}}

4.2 构建filter

一般情况下当我们的过滤条件比较复杂的时候,通过直接写bson是很不方便的,下边的例子里我们通过“go.mongodb.org/mongo-driver/bson”包,实现了将go中的map转换成bson格式的功能,具体请参考以下代码:

import "go.mongodb.org/mongo-driver/bson"

func (conn *MongoConn) buildQueryFilter(userId string, time string) interface{} {
    filterData := make(map[string]interface{})
    filterData["userid"] = userId
    filterData["time"] =time
  
    filter := bson.M{}
    data, err := bson.Marshal(filterData)
    if err != nil {
        klog.Errorf("marshal error: %v", err)
        return filter
    }

    err = bson.Unmarshal(data, filter)
    if err != nil {
        klog.Errorf("unmarshal error: %v", err)
    }
    klog.Infof("filter: %v", filter)
    return filter
}

5 总结

本文简单的总结了个人在项目开发过程中使用mongo-go-driver包的一些经验和心得,如有不当之处,还望不吝赐教。

 类似资料: