MongoDB的Go驅動包
"go.mongodb.org/mongo-driver/bson" //BOSN解析包
"go.mongodb.org/mongo-driver/mongo" //MongoDB的Go驅動包
"go.mongodb.org/mongo-driver/mongo/options"
BSON簡介
BSON是一種類json的一種二進制形式的存儲格式,簡稱Binary JSON。MongoDB使用了BSON這種結構來存儲數據和網絡數據交換。
BSON對應Document
這個概念,因為BSON是schema-free的,所以在MongoDB中所對應的Document
也有這個特征,這里的一個Document
也可以理解成關系數據庫中的一條Record
,只是Document
的變化更豐富一些,Document
可以嵌套。
MongoDB以BSON做為其存儲結構的一個重要原因是它的可遍歷性
。
BSON編碼擴展了JSON表示,使其包含額外的類型,如int、long、date、浮點數和decimal128。
BSON類型
BSON數據的主要類型有:A
,D
,E
,M
和Raw
。其中,A
是數組,D
是切片,M
是映射,D
和M
是Go原生類型。
-
A
類型表示有序的BSON數組。bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}}
-
D
類型表示包含有序元素的BSON文檔。這種類型應該在順序重要的情況下使用。如果元素的順序無關緊要,則應使用M代替。bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
-
M
類型表示無序的映射。bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
-
E
類型表示D里面的一個BSON元素。 -
Raw
類型代表未處理的原始BSON文檔和元素,Raw
系列類型用於驗證和檢索字節切片中的元素。當要查找BSON字節而不將其解編為另一種類型時,此類型最有用。
連接到mongoDB
// 設置mongoDB客戶端連接信息
param := fmt.Sprintf("mongodb://XXX.XXX.XXX.XXX:27017")
clientOptions := options.Client().ApplyURI(param)
// 建立客戶端連接
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
fmt.Println(err)
}
// 檢查連接情況
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
fmt.Println(err)
}
fmt.Println("Connected to MongoDB!")
//指定要操作的數據集
collection := client.Database("ccmsensor").Collection("mtr")
//執行增刪改查操作
// 斷開客戶端連接
err = client.Disconnect(context.TODO())
if err != nil {
log.Fatal(err)
}
fmt.Println("Connection to MongoDB closed.")
增查改刪
假如數據庫中有一些網絡連接數據,來自不同的APP,來自不同的ISP(運營商),類型如下:
type CurlInfo struct {
DNS float64 `json:"NAMELOOKUP_TIME"` //NAMELOOKUP_TIME
TCP float64 `json:"CONNECT_TIME"` //CONNECT_TIME - DNS
SSL float64 `json:"APPCONNECT_TIME"` //APPCONNECT_TIME - CONNECT_TIME
}
type ConnectData struct {
Latency float64 `json:"latency"`
RespCode int `json:"respCode"`
Url string `json:"url"`
Detail CurlInfo `json:"details"`
}
type Sensor struct {
ISP string
Clientutc int64
DataByAPP map[string]ConnectData
}
增加
使用collection.InsertOne()
來插入一條Document
記錄:
func insertSensor(client *mongo.Client, collection *mongo.Collection) (insertID primitive.ObjectID) {
apps := make(map[string]ConnectData, 0)
apps["app1"] = ConnectData{
Latency: 30.983999967575,
RespCode: 200,
Url: "",
Detail: CurlInfo{
DNS: 5.983999967575,
TCP: 10.983999967575,
SSL: 15.983999967575,
},
}
record := &Sensor{
Clientutc: time.Now().UTC().Unix(),
ISP: "China Mobile",
DataByAPP: apps,
}
insertRest, err := collection.InsertOne(context.TODO(), record)
if err != nil {
fmt.Println(err)
return
}
insertID = insertRest.InsertedID.(primitive.ObjectID)
return insertID
}
查詢
這里引入一個filter
來匹配MongoDB數據庫中的Document
記錄,使用bson.D
類型來構建filter
。
timestamp := time.Now().UTC().Unix()
start := timestamp - 180
end := timestamp
filter := bson.D{
{"isp", isp},
{"$and", bson.A{
bson.D{{"clientutc", bson.M{"$gte": start}}},
bson.D{{"clientutc", bson.M{"$lte": end}}},
}},
}
使用collection.FindOne()
來查詢單個Document
記錄。這個方法返回一個可以解碼為值的結果。
func querySensor(collection *mongo.Collection, isp string) {
//查詢一條記錄
//篩選數據
timestamp := time.Now().UTC().Unix()
start := timestamp - 1800
end := timestamp
filter := bson.D{
{"isp", isp},
{"$and", bson.A{
bson.D{{"clientutc", bson.M{"$gte": start}}},
bson.D{{"clientutc", bson.M{"$lte": end}}},
}},
}
var original Sensor
err := collection.FindOne(context.TODO(), filter).Decode(&original)
if err != nil {
fmt.Printf("%s\n", err.Error())
}
fmt.Printf("Found a single document: %+v\n", original)
}
結果為剛剛插入的那一條數據,
Connected to MongoDB!
Found a single document: {ISP:China Mobile Clientutc:1598867346 DataByAPP:map[app1:{Latency:30.983999967575 RespCode:200 Url: Detail:{DNS:5.983999967575 TCP:10.983999967575 SSL:15.983999967575}}]}
Connection to MongoDB closed.
若要提取其中的數據,在querySensor()方法中略作改動,
original := make(map[string]interface{})
var sensorData Sensor
err := collection.FindOne(context.TODO(), filter).Decode(&original)
if err != nil {
fmt.Printf("%s\n", err.Error())
} else {
vstr, okstr := original["isp"].(string)
if okstr {
sensorData.ISP = vstr
}
}
更新
這里仍然使用剛才的filter,並額外需要一個update
。
update := bson.M{
"$set": bson.M{
"isp": ispAfter,
},
}
使用collection.UpdateOne()
更新單個Document
記錄。
func UpdateSensor(collection *mongo.Collection, ispBefore string, ispAfter string) {
//修改一條數據
//篩選數據
timestamp := time.Now().UTC().Unix()
start := timestamp - 1800
end := timestamp
filter := bson.D{
{"isp", ispBefore},
{"$and", bson.A{
bson.D{{"clientutc", bson.M{"$gte": start}}},
bson.D{{"clientutc", bson.M{"$lte": end}}},
}},
}
//更新內容
update := bson.M{
"$set": bson.M{
"isp": ispAfter,
},
}
updateResult, err := collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Matched %v documents and updated %v documents.\n", updateResult.MatchedCount, updateResult.ModifiedCount)
}
刪除
使用collection.DeleteOne()
來刪除一條記錄,仍然使用剛才的filter。
deleteResult, err := collection.DeleteOne(context.TODO(), filter)
if err != nil {
fmt.Printf("%s\n", err.Error())
}
更多操作請見官方文檔。