mongoDB分散式儲存(二)
go客戶端實現mongoDB的增刪改查
所有api的使用和說明都在官方文件: https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#pkg-index
下面只記錄一下專案中用到的簡單的增刪改查操作
可能用過mysql和redis客戶端的不太習慣mongo客戶端的操作,它獲取一個表操作物件分成了幾個部分:獲取客戶端連線、選擇資料庫、選擇表
// 建立連線
client, err := mongo.Connect(context.TODO(),
options.Client().ApplyURI("mongodb://xxx.xxx.xxx.xxx:27017"),
options.Client().SetConnectTimeout(5*time.Second))
if err != nil {
fmt.Println(err)
return
}
// 選擇資料庫
database := client.Database("cron")
// 選擇表log
collection := database.Collection("log")
因為mongo中資料是使用bson格式儲存的,所以在定義插入資料結構體時,需要使用bson標籤進行反射
// 任務的執行時間點 type TimePoint struct { StartTime int64 `bson:"startTime"` EndTime int64 `bson:"endTime"` } // 日誌結構 type logRecord struct { JobName string `bson:"jon_name"` //任務名 Command string `bson:"commond"` // shell命令 Err string`bson:"err"` // 指令碼錯誤 Content string `bson:"content"` //指令碼輸出 TimePoint TimePoint `bson:"timePoint"` //執行時間 }
1. 向mongoDB中插入資料
插入資料是對我們獲取到的表操作物件進行的,具體的插入函式簽名有如下幾個:
func (coll *Collection) InsertMany(ctx context.Context, documents []interface{}, ...) (*InsertManyResult, error) func (coll*Collection) InsertOne(ctx context.Context, document interface{}, opts ...*options.InsertOneOptions) (*InsertOneResult, error)
根據函式名可以看出可以選擇插入一個和多個,opt是options.InsertOneOptions結構體指標,裡面有可選擇的引數
向mongo中插入一個任務日誌:
// 定義資料結構體 record := &logRecord{ JobName: "job10", Command: "ceho hello", Err: "", Content: "hello", TimePoint: TimePoint{ StartTime: time.Now().Unix(), EndTime: time.Now().Unix() + 10, }, } // 插入資料 insertOneResult, err := collection.InsertOne(context.TODO(), record) if err != nil { fmt.Println(err) return } // 預設生成一個全域性唯一的id,12位元組的二進位制 docID := insertOneResult.InsertedID.(primitive.ObjectID) fmt.Println("自增ID:", docID.Hex())
注意insertOneResult只有InsertID這一個屬性,是一個12位元組的二進位制,如果想要變成易讀資料格式需要進行型別斷言,並且使用.Hex()方法來轉換
插入多條資料也是一樣的操作,需要先宣告一個插入資料的切片
// 批量插入多條資料 logArr := []interface{}{record, record, record} insertManyResult, err := collection.InsertMany(context.TODO(), logArr) if err != nil { fmt.Println(err) return } for _, id := range insertManyResult.InsertedIDs { docID := id.(primitive.ObjectID) fmt.Println("自增ID:", docID.Hex()) }
2. 從mongoDB中讀取資料
首先來看一下查詢資料的函式簽名,有很多,大抵就是查詢和更新刪除等操作的組合,其引數列表裡有一個 filter過濾器,這個需要自己定義過濾器,來指明我們需要針對什麼條件來查詢,opts仍然是可選引數,findopt就有很多,分頁limit排序等等,如果需要的話可以看看各個引數的釋義。
func (coll *Collection) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (*Cursor, error) func (coll *Collection) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) *SingleResult func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{}, ...) *SingleResult func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{}, replacement interface{}, ...) *SingleResult func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{}, update interface{}, ...) *SingleResult
首先定義一個簡單的過濾器:
// jobname過濾條件 type FindByJobName struct { JobName string `bson:"jon_name"` } // 按照jobname過濾,找出jobname=job10 cond := &FindByJobName{ JobName: "job10", }
執行find,返回的是一個*mongo.Cursor型別的值,就是一個遊標,類似於mysql中的遊標,之後我們可以使用這個遊標遍歷結果集
skip := int64(0) limit := int64(2) // 查詢 //cursor, err := collection.Find(context.TODO(), bson.D{{"jon_name", "job10"}}) // 這是官方案例中的寫法,顯得不像在寫客戶端 cursor, err := collection.Find(context.TODO(), cond, &options.FindOptions{ Skip: &skip, Limit: &limit, }) defer cursor.Close(context.TODO()) if err != nil { fmt.Println(err) return }
遍歷結果集,得到查詢到的資料
// 遍歷結果集 for cursor.Next(context.TODO()) { record := &logRecord{} // 反序列化bson到結構體物件 err := cursor.Decode(record) if err != nil { fmt.Println(err) return } // 列印結構體 fmt.Println(*record) }
3. 刪除mongoDB中的資料
首先定義一個刪除規則:我們要刪除建立時間小於當前時間的日誌,等同於清空資料庫了。
先來看看刪除的函式簽名,其實和find是類似的,需要一個過濾器
func (coll *Collection) DeleteMany(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (*DeleteResult, error) func (coll *Collection) DeleteOne(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (*DeleteResult, error)
根據刪除規則我們定義一個過濾器,我們要刪除的是建立時間小於當前時間的,那麼在mongo ctl中就應該寫成json表示式
delete({"timePoint.startPoint":{"$lt":當前時間}})
我們可以利用go的bson反射來做到這個表示式的定義,記住反射是怎麼序列化的就行,後面的bson標籤是key
// startTime小於某時間 // {"$lt":timestamp} type TimeBeforeCond struct { Before int64 `bson:"$lt"` } // 定義刪除條件 // {"timePoint.startPoint":{"$lt":timestamp}} type DelCond struct { beforeCond TimeBeforeCond `bson:"timePoint.startTime"` }
現在讓我們執行deletemany操作,返回的*mongo.DeleteResult只有一個屬性就是被刪除了多少行
// 定義刪除條件 delCond := &DelCond{ beforeCond: TimeBeforeCond{ Before: time.Now().Unix(), }, } deleteResult, err := collection.DeleteMany(context.TODO(), delCond) if err != nil { fmt.Println(err) return } fmt.Println("刪除了多少行:", deleteResult.DeletedCount)
以上只是一些go-mongo客戶端的簡單操作,如果有更復雜的需求建議去閱讀官方文件,裡面有每個方法的詳細釋義及example