1. 程式人生 > 實用技巧 >Qmgo 開源了! 更好用的 Go 語言 MongoDB driver

Qmgo 開源了! 更好用的 Go 語言 MongoDB driver

近日,七牛研發團隊開源了Qmgo[1] - Go 語言的 MongoDB driver。一經發布,便受到了「CSDN」、「Go 語言中文網」等多家媒體的報道和技術開發者們的廣泛關注。Qmgo 在設計上參考了老牌的 driver Mgo[3] (比如 Mgo 的鏈式呼叫),基於Mongo 官方 driver[2]實現,但是有著更好的易用性。讓我們一起深度瞭解這一開源專案。
背景
做 Qmgo 的初衷,來自於使用 MongoDB 的 gopher 們共同的困擾,在 MongoDB 的 Go 官方 driver 成型前(v1.0.0 釋出在 2019 年 3 月),一直是 Mgo 一統江湖,出色的介面設計讓其非常流行。七牛做為最早使用 Go 的公司之一,自然也是 Mgo 的深度使用者。

但是 Mgo 已經在 3 年前不再維護,bug 不修復,MongoDB 的新特性自然也無法支援,而官方 driver 的介面設計是出名的不易用。

這樣的背景下,基於滿足下面的需求,Qmgo 誕生了

想要 MongoDB 新特性
想要更穩定的 driver
想要 Mgo 出色的介面設計
想要從 Mgo 遷移到 Qmgo,程式碼改動最小
下面,簡單介紹一下 Qmgo 的特點,詳情可以點選檢視:Qmgo[4]

好用在哪裡?
舉一個多檔案查詢、sort和limit的例子, 說明qmgo和mgo的相似,以及對go.mongodb.org/mongo-driver的改進

官方Driver需要這樣實現

// go.mongodb.org/mongo-driver
// find all 、sort and limit
findOptions := options.Find()
findOptions.SetLimit(7) // set limit
var sorts D
sorts = append(sorts, E{Key: "weight", Value: 1})
findOptions.SetSort(sorts) // set sort

batch := []UserInfo{}
cur, err := coll.Find(ctx, bson.M{"age": 6}, findOptions)
cur.All(ctx, &batch)
Qmgo和mgo更簡單,而且實現相似:

// qmgo
// find all 、sort and limit
batch := []UserInfo{}
cli.Find(ctx, bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)

// mgo
// find all 、sort and limit
coll.Find(bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)
當前支援的功能
文件的增刪改查
索引配置
Sort、Limit、Count、Select
Cursor
聚合Aggregate
使用方法
開始,import並新建連線
import(
"context"

"github.com/qiniu/qmgo"

)
ctx := context.Background()
client, err := qmgo.NewClient(ctx, &qmgo.Config{Uri: "mongodb://localhost:27017"})
db := client.Database("class")
coll := db.Collection("user")
如果你的連線是指向固定的 database 和 collection,我們推薦使用下面的更方便的方法初始化連線,後續操作都基於cli而不用再關心 database 和 collection

cli, err := qmgo.Open(ctx, &qmgo.Config{Uri: "mongodb://localhost:27017", Database: "class", Coll: "user"})
後面都會基於cli來舉例,如果你使用第一種傳統的方式進行初始化,根據上下文,將cli替換成client、db 或 coll即可

在初始化成功後,請defer來關閉連線

defer func() {
if err = cli.Close(ctx); err != nil {
panic(err)
}
}()
建立索引
做操作前,我們先初始化一些資料:

type UserInfo struct {
Name string bson:"name"
Age uint16 bson:"age"
Weight uint32 bson:"weight"
}

var oneUserInfo = UserInfo{
Name: "xm",
Age: 7,
Weight: 40,
}
建立索引

cli.EnsureIndexes(ctx, []string{}, []string{"age", "name,weight"})
插入一個文件
// insert one document
result, err := cli.Insert(ctx, oneUserInfo)
查詢一個文件
// find one document
one := UserInfo{}
err = cli.Find(ctx, bson.M{"name": oneUserInfo.Name}).One(&one)
刪除文件
err = cli.Remove(ctx, bson.M{"age": 7})
插入多條資料
// multiple insert
var batchUserInfoI = []interface{}{
UserInfo{Name: "a1", Age: 6, Weight: 20},
UserInfo{Name: "b2", Age: 6, Weight: 25},
UserInfo{Name: "c3", Age: 6, Weight: 30},
UserInfo{Name: "d4", Age: 6, Weight: 35},
UserInfo{Name: "a1", Age: 7, Weight: 40},
UserInfo{Name: "a1", Age: 8, Weight: 45},
}
result, err = cli.Collection.InsertMany(ctx, batchUserInfoI)
批量查詢、Sort和Limit
// find all 、sort and limit
batch := []UserInfo{}
cli.Find(ctx, bson.M{"age": 6}).Sort("weight").Limit(7).All(&batch)
Count
count, err := cli.Find(ctx, bson.M{"age": 6}).Count()
Update
// UpdateOne one
err := cli.UpdateOne(ctx, bson.M{"name": "d4"}, bson.M{"$set": bson.M{"age": 7}})

// UpdateAll
result, err := cli.UpdateAll(ctx, bson.M{"age": 6}, bson.M{"$set": bson.M{"age": 10}})
Select
err := cli.Find(ctx, bson.M{"age": 10}).Select(bson.M{"age": 1}).One(&one)
Aggregate
matchStage := bson.D{{"$match", []bson.E{{"weight", bson.D{{"$gt", 30}}}}}}
groupStage := bson.D{{"$group", bson.D{{"_id", "$name"}, {"total", bson.D{{"$sum", "$age"}}}}}}
var showsWithInfo []bson.M
err = cli.Aggregate(context.Background(), Pipeline{matchStage, groupStage}).All(&showsWithInfo)

參考資料
[1]
Qmgo: https://github.com/qiniu/qmgo

[2]
Mongo官方driver: https://github.com/mongodb/mongo-go-driver

[3]
Mgo: https://github.com/go-mgo/mgo

[4]
Qmgo: https://github.com/qiniu/qmgo