当前位置: 代码网 > it编程>前端脚本>Golang > go-zero使用goctl生成mongodb的操作使用方法

go-zero使用goctl生成mongodb的操作使用方法

2024年07月05日 Golang 我要评论
mongodb简介mongodb是一种高性能、开源、文档型的nosql数据库,被广泛应用于web应用、大数据以及云计算领域。在使用mongodb之前,需要先在您的系统中安装mongodb。在linux

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的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com