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. 強大的靈活性
MongoDB是一個面向文檔的數(shù)據(jù)庫,它使用BSON(二進制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ù)制和分片機制,可用于處理高并發(fā)的讀寫操作。相比之下,MySQL需要通過SQL查詢語句來讀寫數(shù)據(jù),這通常比MongoDB的操作要慢一些。
3. 分布式擴展性
MongoDB可以輕松地進行水平擴展,即通過添加更多的節(jié)點來增加存儲容量和處理能力。這種分布式架構(gòu)使得MongoDB能夠處理大量數(shù)據(jù)和高并發(fā)請求。與之相比,MySQL在處理大規(guī)模數(shù)據(jù)和高并發(fā)情況下的擴展性有限。
4. 靈活的數(shù)據(jù)模型
MongoDB的數(shù)據(jù)模型允許我們使用嵌套文檔和數(shù)組來表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。這使得數(shù)據(jù)的存儲和查詢更加方便,無需進行多個表之間的連接操作。例如,我們可以在一個文檔中存儲一個訂單及其相關(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語句來進行數(shù)據(jù)的插入和查詢,需要提前定義表結(jié)構(gòu)。
總的來說,MongoDB在靈活性、高性能讀寫、分布式擴展性和靈活的數(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進行model層代碼生成。官網(wǎng)有對MySQL的使用方法,但是沒有對MongoDB的使用進行講解,那么我下面介紹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目錄下生成模型框架代碼,如果需要擴展其他字段類型,直接修改生成的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 filesgo-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)字段不是嚴格按照順序組織時用它。當(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序列化單獨定義標(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)這一點。默認情況下,所有未標(biāo)記的公開字段都會被序列化。
特殊類型處理:對于Go中的某些類型,如時間time.Time,如果沒有使用bson標(biāo)簽指定其為日期類型(如bson:"date"),它們會被序列化為BSON的字符串或其他默認格式,可能不符合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的操作使用方法的詳細內(nèi)容,更多關(guān)于go-zero goctl生成mongodb的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go開發(fā)go-optioner工具實現(xiàn)輕松生成函數(shù)選項模式代碼
go-optioner?是一個在?Go?代碼中生成函數(shù)選項模式代碼的工具,可以根據(jù)給定的結(jié)構(gòu)定義自動生成相應(yīng)的選項代碼,下面就來聊聊go-optioner是如何使用的吧2023-07-07
Golang中struct{}和struct{}{}的區(qū)別解析
這篇文章主要介紹了Golang中struct{}和struct{}{}的區(qū)別,通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
go-zero使用goctl生成mongodb的操作使用方法
mongodb是一種高性能、開源、文檔型的nosql數(shù)據(jù)庫,被廣泛應(yīng)用于web應(yīng)用、大數(shù)據(jù)以及云計算領(lǐng)域,goctl model 為 goctl 提供的數(shù)據(jù)庫模型代碼生成指令,目前支持 MySQL、PostgreSQL、Mongo 的代碼生成,本文給大家介紹了go-zero使用goctl生成mongodb的操作使用方法2024-06-06

