go-zero使用goctl生成mongodb的操作使用方法
MongoDB簡介
mongodb是一種高性能、開源、文檔型的nosql數(shù)據(jù)庫,被廣泛應(yīng)用于web應(yīng)用、大數(shù)據(jù)以及云計算領(lǐng)域。
在使用MongoDB之前,需要先在您的系統(tǒng)中安裝MongoDB。在Linux系統(tǒng)下,可以通過如下命令安裝:
sudo apt-get install mongodb
MongoDB的優(yōu)勢
1. 強(qiáng)大的靈活性
MongoDB是一個面向文檔的數(shù)據(jù)庫,它使用BSON(二進(jìn)制JSON)格式來存儲數(shù)據(jù)。相比之下,MySQL是一個關(guān)系型數(shù)據(jù)庫,使用表格來存儲數(shù)據(jù)。這使得MongoDB更加靈活,可以存儲不同結(jié)構(gòu)的文檔。例如,我們可以在同一個集合中存儲不同類型的文檔,而MySQL需要創(chuàng)建多個表來存儲不同類型的數(shù)據(jù)。
2. 高性能的讀寫操作
由于MongoDB使用BSON格式存儲數(shù)據(jù),并且數(shù)據(jù)存儲在文檔中,它可以更快地讀寫數(shù)據(jù)。此外,MongoDB還支持內(nèi)置的復(fù)制和分片機(jī)制,可用于處理高并發(fā)的讀寫操作。相比之下,MySQL需要通過SQL查詢語句來讀寫數(shù)據(jù),這通常比MongoDB的操作要慢一些。
3. 分布式擴(kuò)展性
MongoDB可以輕松地進(jìn)行水平擴(kuò)展,即通過添加更多的節(jié)點(diǎn)來增加存儲容量和處理能力。這種分布式架構(gòu)使得MongoDB能夠處理大量數(shù)據(jù)和高并發(fā)請求。與之相比,MySQL在處理大規(guī)模數(shù)據(jù)和高并發(fā)情況下的擴(kuò)展性有限。
4. 靈活的數(shù)據(jù)模型
MongoDB的數(shù)據(jù)模型允許我們使用嵌套文檔和數(shù)組來表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。這使得數(shù)據(jù)的存儲和查詢更加方便,無需進(jìn)行多個表之間的連接操作。例如,我們可以在一個文檔中存儲一個訂單及其相關(guān)的所有產(chǎn)品,并且可以輕松地查詢和更新這個文檔。相比之下,MySQL需要通過多個表和連接操作來實現(xiàn)類似的功能。
對比mysql的操作
在數(shù)據(jù)庫的操作上與mysql有很大不同。畢竟一個是非關(guān)系型,一個是關(guān)系型數(shù)據(jù)庫。接下來從python代碼上先來直觀感受下二者的不同。
python操作mogodb示例
# MongoDB示例 # 連接到MongoDB數(shù)據(jù)庫 from pymongo import MongoClient client = MongoClient('mongodb://localhost:27017/') # 獲取數(shù)據(jù)庫和集合對象 db = client['mydb'] collection = db['mycollection'] # 插入一條文檔 data = {'name': 'John', 'age': 25} collection.insert_one(data) # 查詢文檔 result = collection.find_one({'name': 'John'}) print(result) # 關(guān)閉連接 client.close()
mysql的python 示例
-- MySQL示例 -- 連接到MySQL數(shù)據(jù)庫 import mysql.connector cnx = mysql.connector.connect(user='root', password='password', host='localhost', database='mydb') -- 獲取游標(biāo) cursor = cnx.cursor() -- 插入一條記錄 sql = "INSERT INTO mytable (name, age) VALUES (%s, %s)" values = ('John', 25) cursor.execute(sql, values) cnx.commit() -- 查詢記錄 sql = "SELECT * FROM mytable WHERE name = 'John'" cursor.execute(sql) result = cursor.fetchone() print(result) -- 關(guān)閉連接 cursor.close() cnx.close()
通過以上示例,可以看到MongoDB使用了面向文檔的操作方式,數(shù)據(jù)以JSON格式存儲在集合中,并且不需要事先定義表結(jié)構(gòu)。而MySQL需要使用SQL語句來進(jìn)行數(shù)據(jù)的插入和查詢,需要提前定義表結(jié)構(gòu)。
總的來說,MongoDB在靈活性、高性能讀寫、分布式擴(kuò)展性和靈活的數(shù)據(jù)模型方面相對于MySQL有許多優(yōu)勢。當(dāng)處理需要存儲和查詢復(fù)雜數(shù)據(jù)結(jié)構(gòu)、大規(guī)模數(shù)據(jù)和高并發(fā)請求時,MongoDB是一個更好的選擇。
goctl的mongodb代碼生成
goctl model 為 goctl 提供的數(shù)據(jù)庫模型代碼生成指令,目前支持 MySQL、PostgreSQL、Mongo 的代碼生成,MySQL 支持從 sql 文件和數(shù)據(jù)庫連接兩種方式生成,PostgreSQL 僅支持從數(shù)據(jù)庫連接生成。
goctl model 為go-zero下的工具模塊中的組件之一,目前支持MongoDB進(jìn)行model層代碼生成。官網(wǎng)有對MySQL的使用方法,但是沒有對MongoDB的使用進(jìn)行講解,那么我下面介紹goctl model對MongoDB的使用方法。
Mongo 模型層代碼的生成不同于 MySQL,MySQL 可以從 scheme_information 庫中讀取到一張表的信息(字段名稱,數(shù)據(jù)類型,索引等), 而 Mongo 是文檔型數(shù)據(jù)庫,我們暫時無法從 db 中讀取某一條記錄來實現(xiàn)字段信息獲取。
Usage: goctl model mongo [flags] Flags: --branch string The branch of the remote repo, it does work with --remote -c, --cache Generate code with cache [optional] -d, --dir string The target dir -e, --easy Generate code with auto generated CollectionName for easy declare [optional] -h, --help help for mongo --home string The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority --remote string The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure --style string The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md] -t, --type strings Specified model type name
各個參數(shù)的含義,主要用的是 -e -dir -t
-e表示的是生成一個簡單的增刪改查接口,-dir是生成文檔放在的目錄
-t是生成文件的前綴名稱
-c是帶緩存的
如何使用
goctl model mongo -t User -dir model/user
如何生成model層代碼?執(zhí)行以上命令即可,很簡單,不需要提前編寫什么模型文件,以上命令將自動在model/user目錄下生成模型框架代碼,如果需要擴(kuò)展其他字段類型,直接修改生成的usertypes.go文件。
過程如下:
# enter user home $ cd ~ # make dir named demo $ mkdir demo && cd demo # generate mongo code by goctl $ goctl model mongo --type User --dir cache --cache # view layout $ tree . └── cache ├── error.go ├── usermodel.go ├── usermodelgen.go └── usertypes.go 1 directory, 4 files
go-zero中mogodb使用
go-zero中mogodb的基礎(chǔ)使用:
package main import ( "context" "time" "github.com/globalsign/mgo/bson" "github.com/zeromicro/go-zero/core/stores/mon" "go.mongodb.org/mongo-driver/bson/primitive" ) type Roster struct { Id primitive.ObjectID `bson:"_id"` CreateTime time.Time `bson:"createTime"` DisplayName string `bson:"displayName"` } func main() { model := mon.MustNewModel("mongodb://root:example@127.0.0.1:27017", "db", "user") r := &Roster{ Id: primitive.NewObjectID(), CreateTime: time.Now(), DisplayName: "Hello", } ctx := context.Background() _, err := model.InsertOne(ctx, r) if err != nil { panic(err) } update := bson.M{"$set": bson.M{ "displayName": "Hello world", "createTime": time.Now(), }} _, err = model.UpdateByID(ctx, r.Id, update) if err != nil { panic(err) } r.DisplayName = "Hello world!" _, err = model.ReplaceOne(ctx, bson.M{"_id": r.Id}, r) if err != nil { panic(err) } var tr Roster err = model.FindOne(ctx, &tr, bson.M{"_id": r.Id}) if err != nil { panic(err) } }
mongodb官方驅(qū)動使用
再來看下在在golang中的mongodb官方驅(qū)動使用示例:
package main import ( "context" "log" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main() { clientOptions := options.Client().ApplyURI("mongodb://localhost:27017") client, err := mongo.Connect(context.Background(), clientOptions) if err != nil { log.Fatal(err) } defer client.Disconnect(context.Background()) coll := client.Database("your_db_name").Collection("user") // 插入數(shù)據(jù) doc := &user.User{ Id: "1", Name: "Alice", Email: "alice@example.com", } _, err = coll.InsertOne(context.TODO(), doc) if err != nil { log.Fatal(err) } // 查詢數(shù)據(jù) var result user.User err = coll.FindOne(context.TODO(), bson.M{"_id": "1"}).Decode(&result) if err != nil { log.Fatal(err) } log.Printf("Found user: %+v", result) // 更新數(shù)據(jù) updateResult, err := coll.UpdateOne( context.TODO(), bson.M{"_id": "1"}, bson.D{{"$set", bson.D{{"email", "alice.updated@example.com"}}}}, ) if err != nil { log.Fatal(err) } log.Printf("Modified count: %v", updateResult.ModifiedCount) // 刪除數(shù)據(jù) deleteResult, err := coll.DeleteOne(context.TODO(), bson.M{"_id": "1"}) if err != nil { log.Fatal(err) } log.Printf("Deleted count: %v", deleteResult.DeletedCount) }
增刪改查示例
package main import ( "context" "fmt" "log" "time" //"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/bson" ) type User struct { Name string `json:"name"` Email string `json:"email"` Age int `bson:"Agg"` } // ... 上面User結(jié)構(gòu)體定義 ... func main() { // 連接MongoDB clientOptions := options.Client().ApplyURI("mongodb://test1:111111@localhost:27017/?tls=false&authSource=test1") client, err := mongo.Connect(context.Background(), clientOptions) if err != nil { log.Fatal(err) } defer func() { if err = client.Disconnect(context.Background()); err != nil { log.Fatal(err) } }() // 解析JSON字符串到User結(jié)構(gòu)體(假設(shè)已經(jīng)完成) user := User{Name: "Alice", Email: "alice@example.com",Age:22} // 選擇數(shù)據(jù)庫和集合 collection := client.Database("test1").Collection("users") // 插入文檔 insertResult, err := collection.InsertOne(context.TODO(), user) if err != nil { log.Fatal(err) } fmt.Println("Inserted ID:", insertResult.InsertedID) // 插入文檔 doc := bson.D{{"name", "Alice1"}, {"age", 30}, {"createdAt", time.Now()}} insertResult, err = collection.InsertOne(context.TODO(), doc) if err != nil { log.Fatal(err) } fmt.Println("Inserted ID:", insertResult.InsertedID) // 更新文檔 filter := bson.D{{"name", "Alice1"}} update := bson.D{{"$set", bson.D{{"age", 31}}}} updateResult, err := collection.UpdateOne(context.TODO(), filter, update) if err != nil { log.Fatal(err) } fmt.Println("Modified Count:", updateResult.ModifiedCount) // 刪除文檔 filter = bson.D{{"age", 22}} deleteResult, err := collection.DeleteOne(context.TODO(), filter) if err != nil { log.Fatal(err) } fmt.Println("Deleted Count:", deleteResult.DeletedCount) // 查找單個文檔 var singleResult bson.M err = collection.FindOne(context.TODO(), bson.D{}).Decode(&singleResult) if err != nil { log.Fatal(err) } fmt.Println("Single Document:", singleResult) // 查找所有文檔 cursor, err := collection.Find(context.TODO(), bson.D{}) if err != nil { log.Fatal(err) } defer cursor.Close(context.TODO()) for cursor.Next(context.TODO()) { var result bson.M err := cursor.Decode(&result) if err != nil { log.Fatal(err) } fmt.Println("Document:", result) } // 過濾查找 filteredCursor, err := collection.Find(context.TODO(), bson.D{{"age", bson.D{{"$gt", 31}}}}) if err != nil { log.Fatal(err) } defer filteredCursor.Close(context.TODO()) for filteredCursor.Next(context.TODO()) { var filteredDoc bson.M err := filteredCursor.Decode(&filteredDoc) if err != nil { log.Fatal(err) } fmt.Println("Filtered Document:", filteredDoc) } }
注意事項
示例中的bson.D 和 bson.M 都是Go語言中用于表示MongoDB的BSON文檔的數(shù)據(jù)類型,但它們之間存在一些關(guān)鍵的區(qū)別 。
bson.D (Ordered Dictionary),bson.D是一個有序的字典類型,其中元素按照它們被定義的順序排列。它是一個包含了鍵值對的切片,其中每一個元素都是一個兩元素的數(shù)組,第一個元素是字符串(字段名),第二個元素可以是任意類型(字段值)。當(dāng)你需要按照特定順序來定義BSON文檔的字段時,使用它。
bson.M (Map),bson.M是一個無序的映射類型,基于Go語言的map[string]interface{},用于表示不關(guān)心順序的鍵值對集合。用途: 更適合用于構(gòu)建動態(tài)查詢條件或者不需要保持特定字段順序的情況。如:
query := bson.M{"name": "Alice", "age": bson.M{"$gt": 30}}
對于大多數(shù)常規(guī)的查詢構(gòu)建,特別是當(dāng)字段不是嚴(yán)格按照順序組織時用它。當(dāng)文檔的結(jié)構(gòu)是動態(tài)生成或者需要頻繁修改時,bson.M提供了更靈活的鍵值對添加和管理方式。
在Go語言中,使用mongo-go-drive驅(qū)動,需r將JSON字符串轉(zhuǎn)換為結(jié)構(gòu)體,才存儲到MongoDB中。如果你有一個JSON字符串,需要將其解析到Go的結(jié)構(gòu)體中。
直接將JSON字符串存入MongoDB并非最佳實踐,因為MongoDB使用BSON(Binary JSON)作為存儲格式,雖然BSON與JSON相似,但直接存儲JSON字符串會導(dǎo)致數(shù)據(jù)以文本形式存在,喪失了BSON的一些優(yōu)勢,如高效的查詢和索引能力。
然而,如果你確實需要將JSON字符串原樣存儲到MongoDB中(例如,作為文檔的一個字段),可以通過將JSON字符串作為文檔的一個鍵值對插入。
如果golang的結(jié)構(gòu)體不增加bson標(biāo)簽,能否成功寫入mongodb?
為何有了json標(biāo)簽,還要bson標(biāo)簽?zāi)兀?/p>
盡管從表面上看,為BSON序列化單獨(dú)定義標(biāo)簽似乎增加了些冗余,但實際上,這樣的設(shè)計提高了代碼的清晰度、靈活性和對MongoDB特性的直接支持。
即使Go語言的結(jié)構(gòu)體沒有顯式地增加bson標(biāo)簽,你仍然可以成功地將結(jié)構(gòu)體實例寫入MongoDB。mongo-go-driver會按照結(jié)構(gòu)體字段的名稱來映射到BSON文檔的鍵名。但是,這種方式有一些限制和注意事項:
字段名稱:如果沒有bson標(biāo)簽,MongoDB驅(qū)動會直接使用Go結(jié)構(gòu)體字段名作為BSON文檔的鍵。這意味著字段名必須符合MongoDB的命名規(guī)范,且大小寫敏感性會得到保留。這可能導(dǎo)致查詢時需要精確匹配字段名的大小寫。
嵌套結(jié)構(gòu)體:對于嵌套的結(jié)構(gòu)體字段,如果不使用bson標(biāo)簽來指定嵌套層次或別名,那么嵌套結(jié)構(gòu)體的字段會扁平化到同一層級,可能導(dǎo)致數(shù)據(jù)結(jié)構(gòu)與預(yù)期不符。
忽略字段:如果想讓某些字段不被序列化到MongoDB,沒有bson標(biāo)簽就無法直接實現(xiàn)這一點(diǎn)。默認(rèn)情況下,所有未標(biāo)記的公開字段都會被序列化。
特殊類型處理:對于Go中的某些類型,如時間time.Time,如果沒有使用bson標(biāo)簽指定其為日期類型(如bson:"date"),它們會被序列化為BSON的字符串或其他默認(rèn)格式,可能不符合MongoDB的最佳實踐。
因此,雖然不加bson標(biāo)簽可以工作,但在很多實際應(yīng)用場景中,為了更好地控制數(shù)據(jù)的序列化和反序列化行為,以及確保數(shù)據(jù)的一致性和查詢效率,建議還是使用bson標(biāo)簽來明確指定字段映射規(guī)則。
model模型的方式使用
具體的實例化方法,參照goctl模型層的使用,在internal/svc/servicecontext.go 中完成模型的連接和實例化。比較簡單,具體根據(jù)需要更改。
package svc import "myprj/internal/config" //手動代碼 import "myprj/rpc/model" type ServiceContext struct { Config config.Config Model model.NewUserModel// 手動代碼 } func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: c, Model: model.NewUserModel(c.DataSource, c.Cache), // 手動代碼 } }
以上就是go-zero使用goctl生成mongodb的操作使用方法的詳細(xì)內(nèi)容,更多關(guān)于go-zero goctl生成mongodb的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言映射內(nèi)部實現(xiàn)及基礎(chǔ)功能實戰(zhàn)
這篇文章主要為大家介紹了Go語言映射的內(nèi)部實現(xiàn)和基礎(chǔ)功能實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2022-03-03Go語言實現(xiàn)一個簡單生產(chǎn)者消費(fèi)者模型
本文主要介紹了Go語言實現(xiàn)一個簡單生產(chǎn)者消費(fèi)者模型,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12詳解go-zero如何使用validator進(jìn)行參數(shù)校驗
這篇文章主要介紹了如何使用validator庫做參數(shù)校驗的一些十分實用的使用技巧,包括翻譯校驗錯誤提示信息、自定義提示信息的字段名稱、自定義校驗方法等,感興趣的可以了解下2024-01-017分鐘讀懂Go的臨時對象池pool以及其應(yīng)用場景
這篇文章主要給大家介紹了關(guān)于如何通過7分鐘讀懂Go的臨時對象池pool以及其應(yīng)用場景的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或使用Go具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧2018-11-11Go語言Elasticsearch數(shù)據(jù)清理工具思路詳解
這篇文章主要介紹了Go語言Elasticsearch數(shù)據(jù)清理工具思路詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10Golang拾遺之實現(xiàn)一個不可復(fù)制類型詳解
在這篇文章中我們將實現(xiàn)一個無法被復(fù)制的類型,順便加深對引用類型、值傳遞以及指針的理解。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-02-02go語言在請求http時加入自定義http header的方法
這篇文章主要介紹了go語言在請求http時加入自定義http header的方法,實例分析了Go語言http請求的原理與操作技巧,需要的朋友可以參考下2015-03-03