MongoDB简介
mongodb是一种高性能、开源、文档型的nosql数据库,被广泛应用于web应用、大数据以及云计算领域。
在使用MongoDB之前,需要先在您的系统中安装MongoDB。在Linux系统下,可以通过如下命令安装:
sudo apt-get install mongodb
MongoDB的优势
1. 强大的灵活性
MongoDB是一个面向文档的数据库,它使用BSON(二进制JSON)格式来存储数据。相比之下,MySQL是一个关系型数据库,使用表格来存储数据。这使得MongoDB更加灵活,可以存储不同结构的文档。例如,我们可以在同一个集合中存储不同类型的文档,而MySQL需要创建多个表来存储不同类型的数据。
2. 高性能的读写操作
由于MongoDB使用BSON格式存储数据,并且数据存储在文档中,它可以更快地读写数据。此外,MongoDB还支持内置的复制和分片机制,可用于处理高并发的读写操作。相比之下,MySQL需要通过SQL查询语句来读写数据,这通常比MongoDB的操作要慢一些。
3. 分布式扩展性
MongoDB可以轻松地进行水平扩展,即通过添加更多的节点来增加存储容量和处理能力。这种分布式架构使得MongoDB能够处理大量数据和高并发请求。与之相比,MySQL在处理大规模数据和高并发情况下的扩展性有限。
4. 灵活的数据模型
MongoDB的数据模型允许我们使用嵌套文档和数组来表示复杂的数据结构。这使得数据的存储和查询更加方便,无需进行多个表之间的连接操作。例如,我们可以在一个文档中存储一个订单及其相关的所有产品,并且可以轻松地查询和更新这个文档。相比之下,MySQL需要通过多个表和连接操作来实现类似的功能。
对比mysql的操作
在数据库的操作上与mysql有很大不同。毕竟一个是非关系型,一个是关系型数据库。接下来从python代码上先来直观感受下二者的不同。
python操作mogodb示例
# MongoDB示例 # 连接到MongoDB数据库 from pymongo import MongoClient client = MongoClient('mongodb://localhost:27017/') # 获取数据库和集合对象 db = client['mydb'] collection = db['mycollection'] # 插入一条文档 data = {'name': 'John', 'age': 25} collection.insert_one(data) # 查询文档 result = collection.find_one({'name': 'John'}) print(result) # 关闭连接 client.close()
mysql的python 示例
-- MySQL示例 -- 连接到MySQL数据库 import mysql.connector cnx = mysql.connector.connect(user='root', password='password', host='localhost', database='mydb') -- 获取游标 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) -- 关闭连接 cursor.close() cnx.close()
通过以上示例,可以看到MongoDB使用了面向文档的操作方式,数据以JSON格式存储在集合中,并且不需要事先定义表结构。而MySQL需要使用SQL语句来进行数据的插入和查询,需要提前定义表结构。
总的来说,MongoDB在灵活性、高性能读写、分布式扩展性和灵活的数据模型方面相对于MySQL有许多优势。当处理需要存储和查询复杂数据结构、大规模数据和高并发请求时,MongoDB是一个更好的选择。
goctl的mongodb代码生成
goctl model 为 goctl 提供的数据库模型代码生成指令,目前支持 MySQL、PostgreSQL、Mongo 的代码生成,MySQL 支持从 sql 文件和数据库连接两种方式生成,PostgreSQL 仅支持从数据库连接生成。
goctl model 为go-zero下的工具模块中的组件之一,目前支持MongoDB进行model层代码生成。官网有对MySQL的使用方法,但是没有对MongoDB的使用进行讲解,那么我下面介绍goctl model对MongoDB的使用方法。
Mongo 模型层代码的生成不同于 MySQL,MySQL 可以从 scheme_information 库中读取到一张表的信息(字段名称,数据类型,索引等), 而 Mongo 是文档型数据库,我们暂时无法从 db 中读取某一条记录来实现字段信息获取。
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
各个参数的含义,主要用的是 -e -dir -t
-e表示的是生成一个简单的增删改查接口,-dir是生成文档放在的目录
-t是生成文件的前缀名称
-c是带缓存的
如何使用
goctl model mongo -t User -dir model/user
如何生成model层代码?执行以上命令即可,很简单,不需要提前编写什么模型文件,以上命令将自动在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 files
go-zero中mogodb使用
go-zero中mogodb的基础使用:
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官方驱动使用
再来看下在在golang中的mongodb官方驱动使用示例:
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") // 插入数据 doc := &user.User{ Id: "1", Name: "Alice", Email: "alice@example.com", } _, err = coll.InsertOne(context.TODO(), doc) if err != nil { log.Fatal(err) } // 查询数据 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) // 更新数据 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) // 删除数据 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结构体定义 ... 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结构体(假设已经完成) user := User{Name: "Alice", Email: "alice@example.com",Age:22} // 选择数据库和集合 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文档的数据类型,但它们之间存在一些关键的区别 。
bson.D (Ordered Dictionary),bson.D是一个有序的字典类型,其中元素按照它们被定义的顺序排列。它是一个包含了键值对的切片,其中每一个元素都是一个两元素的数组,第一个元素是字符串(字段名),第二个元素可以是任意类型(字段值)。当你需要按照特定顺序来定义BSON文档的字段时,使用它。
bson.M (Map),bson.M是一个无序的映射类型,基于Go语言的map[string]interface{},用于表示不关心顺序的键值对集合。用途: 更适合用于构建动态查询条件或者不需要保持特定字段顺序的情况。如:
query := bson.M{"name": "Alice", "age": bson.M{"$gt": 30}}
对于大多数常规的查询构建,特别是当字段不是严格按照顺序组织时用它。当文档的结构是动态生成或者需要频繁修改时,bson.M提供了更灵活的键值对添加和管理方式。
在Go语言中,使用mongo-go-drive驱动,需r将JSON字符串转换为结构体,才存储到MongoDB中。如果你有一个JSON字符串,需要将其解析到Go的结构体中。
直接将JSON字符串存入MongoDB并非最佳实践,因为MongoDB使用BSON(Binary JSON)作为存储格式,虽然BSON与JSON相似,但直接存储JSON字符串会导致数据以文本形式存在,丧失了BSON的一些优势,如高效的查询和索引能力。
然而,如果你确实需要将JSON字符串原样存储到MongoDB中(例如,作为文档的一个字段),可以通过将JSON字符串作为文档的一个键值对插入。
如果golang的结构体不增加bson标签,能否成功写入mongodb?
为何有了json标签,还要bson标签呢?
尽管从表面上看,为BSON序列化单独定义标签似乎增加了些冗余,但实际上,这样的设计提高了代码的清晰度、灵活性和对MongoDB特性的直接支持。
即使Go语言的结构体没有显式地增加bson标签,你仍然可以成功地将结构体实例写入MongoDB。mongo-go-driver会按照结构体字段的名称来映射到BSON文档的键名。但是,这种方式有一些限制和注意事项:
字段名称:如果没有bson标签,MongoDB驱动会直接使用Go结构体字段名作为BSON文档的键。这意味着字段名必须符合MongoDB的命名规范,且大小写敏感性会得到保留。这可能导致查询时需要精确匹配字段名的大小写。
嵌套结构体:对于嵌套的结构体字段,如果不使用bson标签来指定嵌套层次或别名,那么嵌套结构体的字段会扁平化到同一层级,可能导致数据结构与预期不符。
忽略字段:如果想让某些字段不被序列化到MongoDB,没有bson标签就无法直接实现这一点。默认情况下,所有未标记的公开字段都会被序列化。
特殊类型处理:对于Go中的某些类型,如时间time.Time,如果没有使用bson标签指定其为日期类型(如bson:"date"),它们会被序列化为BSON的字符串或其他默认格式,可能不符合MongoDB的最佳实践。
因此,虽然不加bson标签可以工作,但在很多实际应用场景中,为了更好地控制数据的序列化和反序列化行为,以及确保数据的一致性和查询效率,建议还是使用bson标签来明确指定字段映射规则。
model模型的方式使用
具体的实例化方法,参照goctl模型层的使用,在internal/svc/servicecontext.go 中完成模型的连接和实例化。比较简单,具体根据需要更改。
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的操作使用方法的详细内容,更多关于go-zero goctl生成mongodb的资料请关注其它相关文章!