go 数据库MongoDB

10 篇文章 0 订阅

MongoDB的连接是通过url进行添加的,
MongoDB创建数据库,后端通过url和数据库名完成连接
数据的表在MongoDB中叫集台
在go中,可以初始化连接单表

但是连接有一个坑

{
  "URL": "mongodb://today:today123@10.206.28.25:27017,10.206.28.26:27017,10.206.28.196:27017/today?replicaSet=replSet",
  "Database": "today"
}
{
  "URL": "mongodb://root:sf123456@10.206.53.156:27017,10.206.53.157:27017,10.206.53.158:27017/today?authSource=admin",
  "Database": "today"
}

第一个连接是普通用户连接,第二个用户是管理员连接,在go启动连接后,err是nil,也就是没有问题,但是入库就出现了连接超时的情况,,原因就是使用的是管理员账号,需要加配置authSource=admin

	//链接mongoDB相关设置,链接地址
	var clientOptions = options.Client().ApplyURI(mongoConfig.URL)
	Client, err := mongo.Connect(context.TODO(), clientOptions)
	fmt.Println("mongodb连接mongoConfig.URL:", mongoConfig.URL)
	fmt.Println("mongodb连接:", err)
	//按钮信息集合
	ActionColl = Client.Database(mongoConfig.Database).Collection("action_info")

注意问题

当使用 result := util.UserBizId.FindOne(context.TODO(), filter)
result.Err()是用来判断是否异常,包括查找不到文档,但是
result, err := util.UserBizId.Find(context.TODO(), filter, nil)
if err != nil {
return userBizeids, err
}
这种情况如果查不到数据并不会报err,所以拿到的数据应该二次判断。这里的问题可能在于结构问题
defer result.Close(context.TODO())
for result.Next(context.TODO()) {
var userBizeid model.UserBizid
err = result.Decode(&userBizeid)
//err = tabs.Decode(&item.PrimaryId)
if err != nil {
return userBizeids, err
}
userBizeids = append(userBizeids, userBizeid)
}
这种结构可能导致无法预知是否又下一个文档数据。

不懂就看菜鸟教程(查了半天索引命中没有找到,这里就看到了)
https://www.runoob.com/mongodb/mongodb-advanced-indexing.html

通过检查索引的生效,可以看出,索引是唯一的

db.getCollection("user_bizid").find({"updateTime":{"$gte": 1, "$lte": 2}}).explain();

db.getCollection("user_bizid").createIndex({"updateTime":1,"zSetType":1});

关于find的查找问题

查找所有

db.CustomSendFindMany(context.Background(), bson.M{})

正常情况下,下面的代码是可以解析的,但是Decode是必须针对确定的结构才能很好的解析

func BackgroundPageGroupConfigFindMany(ctx context.Context, filter bson.M) ([]BackgroundPageGroupConfig, error) {
	var backgrounds []BackgroundPageGroupConfig
	result, err := util.BackgroundPageGroupConfig.Find(ctx, filter)
	//result, err := util.BackgroundPageGroupConfig.Find(ctx, filter, nil)
	if err != nil {
		return backgrounds, err
	}
	defer result.Close(ctx)
	for result.Next(ctx) {
		var background BackgroundPageGroupConfig
		err = result.Decode(&background)
		//err = tabs.Decode(&item.PrimaryId)
		if err != nil {
			return backgrounds, err
		}
		backgrounds = append(backgrounds, background)
	}
	return backgrounds, err
}

修复,采用result.Current.String()做json处理


	for result.Next(ctx) {
		var background BackgroundPageGroupConfig
		var get = make(map[string]interface{})
		result.Decode(&get)
		marshal, err := json.Marshal(get)
		if err!=nil {
			logger.Info("BackgroundPageGroupConfigFindMany:json Marshal解析异常",err)
			continue
		}
		err = json.Unmarshal(marshal, &background)
		if err!=nil {
			logger.Info("BackgroundPageGroupConfigFindMany:json Unmarshal解析异常",err)
			continue
		}
		backgrounds = append(backgrounds, background)
	}

关于mongodb的id

如果id是自定义一个string,这个时候可以通过string类型查找,但是如果是primitive.ObjectID,这个时候需要考虑转换

// string 转 ObjectID
obj_id, e := primitive.ObjectIDFromHex(xxxStr)
	if e != nil {
		//处理错误信息
	}

// ObjectID 转  string 
xxxStr := obj_id.Hex()

添加后返回id

返回类型是interface,但是最后成功后是object类型

func ProcessCategoryAdd(ctx context.Context, processCategory *model.ProcessCategory)(interface{},error) {
	result, err := util.ProcessCategory.InsertOne(ctx, processCategory)
	if err != nil {
		return nil,err
	}
	if result.InsertedID != nil {
		logger.Info("Insert successfully. ID: %v", result.InsertedID)
	}
	return result.InsertedID ,nil
}

processCategoryId, err := db.ProcessCategoryAdd(ctx, &processCategory)
objectID := processCategoryId.(primitive.ObjectID)
err = db.ProcessCategoryIdUpdate(ctx, in, userId, objectID.Hex())

模糊查找

	flowKeyM, err := db.BackgroundPageGroupFindMany(context.Background(), bson.M{"flowKey": bson.M{"$regex": "104"}})

索引的底层研究

https://blog.csdn.net/duzm200542901104/article/details/81910509

唯一索引,稀疏索引

https://www.jb51.net/article/154610.htm

db.getCollection("test").createIndex( { "phone": 1 }, { sparse: true,unique: true } )

db.getCollection("theme_group_id").createIndex( { "customId": 1 }, { sparse: true,unique: true } )
db.getCollection("theme_group_id").createIndex( { "appId": 1 ,"runId":1}, { sparse: true,unique: true } )

索引是数组

注意不能出现两个索引都是数组的情况,只能是有一个

使用函数实现一些数据库操作

//分组实现数据的筛选,然后搬迁数据
db.theme_group_record.aggregate([{
KaTeX parse error: Expected '}', got 'EOF' at end of input: … _id: {runId: "runId", appId: “$appId”},
}
}]).forEach(
function(d){
db.getCollection(“gn”).insert({‘runId’:d._id.runId,‘appId’:d._id.appId,‘customId’:d._id.runId});
});

批量处理

当文档新增字段的时候,会发现没有像mysql数据库那样会给旧数据一个默认值,这个时候就需要做批量更新的处理


db.getCollection('sfecp_button_record').find({"recordType": "consultation"}).forEach(
 
   function(item){                
 
       db.getCollection('sfecp_button_record').update({"_id":item._id},{$set:{"appId":"ecp"}})
 
   }
)

排序字段不用加索引

以下命令查看的结果"indexName": “runId_1”,只有runId索引生效,所以排序字段不在索引的范围,

db.getCollection("theme_group_record").createIndex({"runId":1});
db.getCollection("theme_group_record").createIndex({"runId":1,"updateTime":1});
db.getCollection('theme_group_record').find({"runId":1234567}).sort({updateTime:-1}).explain()

添加索引

查看索引

db.user.getIndexes()

添加索引,一个或者联合索引

db.user.ensureIndex({“name”:1,“age”:1})
添加二级的索引
db.business_data_his.createIndex({“data.version”:1})

修改脚本

db.event_group.update({‘groupType’:‘taskCcMe’},{$set:{‘groupName.zh-CN’:‘任务(我关注)’,‘groupName.zh-HK’:‘任务(我關注)’,‘groupName.en-US’:‘Task(I
care)’}});

查数组对象某个字段的

icons.id
icons是一个数组,数组的对象里有个字段是id

{
	"collection":"business_data_user",
	"filter":{"icons.id":"5ec3d820e9403ba9bc0074da"}
}
模糊查询

采用正则表达式,如果是mongodb中的使用方法是:

db.article.find({“title”: {$regex: /a/, $options: “im”}})

但是在golang中,bson.M{“title”: bson.M{“ r e g e x " : " / a / " , " regex": "/a/", " regex":"/a/","options”: “im”}} 失效
找到了primitive.Regex和bson.Regex使用无效

灵机一动

如果查不到数据,结果是怎样的?

这个时候err!=nil,内容是no document in result

update := db.BusinessDataPageUpdate(pageDO)

更新数据失败和成功

对于数据的更新,出现失败的情况。这里的pageDo是一个map,更新是根据id对map中的字段进行了更新。id值正确,但是更新失败了,为什么呢?
这是因为保存的时候采用了map保存,也就是说结构是不确定的,这也是mongodb跟mysql的巨大差别之一,所以同一个集合中可以保存任意形式的结构。但是问题来了,如果这个时候进行修改呢?这个时候map是一个确定的结构体,所以如果被修改的数据不是这种结构,将会导致更新失败,所以决定采用删除的方式。

但是,,,,,在page里的某个字段下,有一个包含数组的,添加一个新的对象到数组中,这个时候,却可以更新,这是因为对于page的数据来说,跟新前后是结构体是一样的,用java来说就是具有相同的类型,也就是类相同。

使用分布式锁进行对数据唯一操作

实际的结果出现了被操作了两次,为啥呢,因为作为标识的更新时间没有修改,所以,,,等于一直可以被修改。

go

//链接mongoDB相关设置,链接地址
	var clientOptions = options.Client().ApplyURI(mongoConfig.URL)
	Client, _ = mongo.Connect(context.TODO(), clientOptions)
	//读取的dataBase和集合名称
	TestCon = Client.Database(mongoConfig.Database).Collection("test")

存储数据的时候,是直接存储一个data

func Add(coll *mongo.Collection, data interface{}) error {
	result, err := coll.InsertOne(context.TODO(), data)
	if err != nil {
		return err
	}
	if result.InsertedID != nil {
		logger.Info("Insert successfully. ID: %v", result.InsertedID)
		//data.Id = result.InsertedID.(primitive.ObjectID)
	}
	return nil
}

数据获取的时候,通过filter数据库中某个字段的值来进行获取data

func GetOne(coll *mongo.Collection, filter bson.M, opts ...*options.FindOneOptions) ([]byte, error) {

	one := coll.FindOne(context.TODO(), filter, opts...)
	var data []byte
	err := one.Decode(&data)
	//封装数据
	return data, err
}
//注意如果这里要进行判断是否有数据,并不是用判断nil,而是判断结果的字段Err,
//但是这里用Decode完全没有毛病,查看底层代码会发现会对Err进行判断
	result := util.UserBizId.FindOne(context.TODO(), bson.M{"appId":"abc"})
	println(result == nil)//永远都是false
	println(result.Err())
package db

import (
	"context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gotoday/model"
	"gotoday/util"
)

//添加数据
func UserBizIdAdd(data *model.UserBizid) error {
	result, err := util.UserBizId.InsertOne(context.TODO(), data)
	if err != nil {
		return err
	}
	if result.InsertedID != nil {
		logger.Info("Insert successfully. ID: %v", result.InsertedID)
	}
	return nil
}

func UserBizIdDel(filter bson.M) error {
	_, err := util.UserBizId.DeleteMany(context.TODO(), filter)
	if err != nil {
		return err
	}
	return nil
}

//查找数据
func UserBizIdFindOne(filter bson.M) model.UserBizid {
	var userBizeid model.UserBizid
	result := util.UserBizId.FindOne(context.TODO(), filter)
	if result == nil {
		return userBizeid
	}
	result.Decode(&userBizeid)
	//封装数据
	return userBizeid
}

//更新数据
func UserBizIdUpdate(data model.UserBizid) error {
	filter := bson.M{"_id": data.Id}
	update_content := bson.D{
		{"$set", bson.D{
			{"userId", data.UserId},
			{"bizId", data.BizId},
			{"zSetType", data.ZSetType},
			{"updateTime", data.UpdateTime},
		}},
	}
	_, err := util.UserBizId.UpdateOne(context.TODO(), filter, update_content)
	if err != nil {
		return err
	}
	return nil
}

//更新数据
func UserBizIdFindAndUpdate(data model.UserBizid) model.UserBizid {
	var userBizeid model.UserBizid
	filter := bson.M{"userId": data.UserId, "bizId": data.BizId, "zSetType": data.ZSetType}
	update_content := bson.D{
		{"$set", bson.D{
			{"updateTime", data.UpdateTime},
		}},
	}
	result := util.UserBizId.FindOneAndUpdate(context.TODO(), filter, update_content)
	if result == nil {
		return userBizeid
	}
	result.Decode(&userBizeid)
	//封装数据
	return userBizeid
}

func GetUserBizidList(filter bson.M) ([]model.UserBizid, error) {
	var userBizids []model.UserBizid
	option := new(options.FindOptions)
	sortMap := make(map[string]interface{})
	sortMap["updateTime"] = 1
	option.Sort = sortMap
	results, err := util.UserBizId.Find(context.TODO(), filter, option)
	if err != nil {
		return userBizids, err
	}
	defer results.Close(context.TODO())
	for results.Next(context.TODO()) {
		var userBizid model.UserBizid
		err = results.Decode(&userBizid)
		if err != nil {
			return userBizids, err
		}
		userBizids = append(userBizids, userBizid)
	}
	return userBizids, nil
}

func AppendList(list *[]model.UserBizid, filter bson.M, bizMap *map[string]string) {
	results, err := GetUserBizidList(filter)
	if err != nil {
		return
	}
	for _, v := range results {
		if value, ok := (*bizMap)[v.BizId]; ok {
			logger.Info("去重", value)
		} else {
			*list = append(*list, v)
			(*bizMap)[v.BizId] = v.BizId
		}
	}
}

查找的filter

	filter3 := bson.M{"userId": strconv.FormatInt(userId, 10), "companyId": strconv.FormatInt(companyId, 10), "zSetType": constant.TM_END_BASE, "updateTime": bson.M{"$gte": start, "$lte": end}}

设计一个动态查询的接口
先看入参

{
	"collection":"template_relation",//集合名
	"filter":{"status":{"completed":true}}//查表的filter,这里实现第二级的判断条件
}

gin框架代码

func SelectFromCollection(ctx *gin.Context) {
	//验签
	flag, msg := check(ctx)
	if !flag {
		util.Response(ctx, 400, msg, "")
		return
	}
	var param param.FromCollectionParam
	err := ctx.BindJSON(&param)
	if err != nil {
		logger.Error("请求参数格式不正确:", err)
		util.Response(ctx, 500, "请求参数格式不正确", nil)
		return
	}
	collName := param.Collection
	var coll *mongo.Collection
	coll = util.Client.Database(config.MongoConfiguration.Database).Collection(collName)
	filter := param.Filter
	results, err := coll.Find(context.TODO(), filter)
	if err != nil {
		util.Response(ctx, 400, "查库失败", "")
		return
	}
	defer results.Close(context.TODO())
	var datas []interface{}
	for results.Next(context.TODO()) {
		var dataMap = make(map[string]interface{})
		err = results.Decode(&dataMap)
		if err != nil {
			logger.Info("数据解析异常")
		} else {
			datas = append(datas, dataMap)
		}
	}
	util.Response(ctx, 200, "ok", datas)
}

func check(ctx *gin.Context) (flag bool, msg string) {
	appKey := ctx.Request.Header.Get("appKey")
	timestamp := ctx.Request.Header.Get("timestamp")
	nonce := ctx.Request.Header.Get("nonce")
	checksum := ctx.Request.Header.Get("checksum")
	if "gotoday" != appKey {
		return false, "appKey不正确"
	}
	//验签的过期
	
	hash := sha1.New()
	hash.Write([]byte("cc" + nonce + timestamp))
	result := fmt.Sprintf("%x", hash.Sum(nil))
	if result != checksum {
		return false, "验证不通过"
	}
	return true, "ok"
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值