1. 程式人生 > 其它 >mongoDB分散式儲存(二)

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