当前位置:网站首页>使用MongoDB官方go库操作MongoDB原创
使用MongoDB官方go库操作MongoDB原创
2022-06-12 17:33:00 【二丫讲梵】
官方库更新很及时,兼容性最好,官方提供的文档也比较全,社区比较活跃,因此比较建议使用这个库来进行交互。
初始化连接
初始化连接方法如下:
package public
import (
"context"
"log"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func InitDb() *mongo.Client {
uri := "mongodb://root:[email protected]:27017"
if uri == "" {
log.Fatal("You must set your 'MONGODB_URI' environmental variable. See\n\t https://docs.mongodb.com/drivers/go/current/usage-examples/#environment-variable")
}
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
panic(err)
}
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
return client
}此处返回一个客户端对象, 然后通过里边的方法指定库和表。
指定库:
var DB *mongo.Database
DB = public.InitDb().Database("class") // 指定库名为 class指定表:
table := DB.Collection("user") // 指定表名为user插入
插入单条
首次示例提供完整示例,后续仅提供方法。
package main
import (
"context"
"learn-mongo/public"
"go.mongodb.org/mongo-driver/mongo"
)
var DB *mongo.Database
var ctx = context.Background()
func init() {
// 初始化数据库
DB = public.InitDb().Database("class")
}
// AddOne 插入单条
func AddOne() {
coll := DB.Collection("testdata")
doc := make(map[string]interface{})
doc["title"] = "test"
doc["content"] = "this is a test"
_, err := coll.InsertOne(ctx, doc)
if err != nil {
panic(err)
}
}
func main() {
AddOne()
defer func() {
if err := public.InitDb().Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
}其中一些已经说明过了,暂不多赘述,运行之后,可以在表中看到此条数据:
db.getCollection('testdata').find({"title":"test"})
/* 1 */
{
"_id" : ObjectId("61f2389ca0cd2ab482132e57"),
"title" : "test",
"content" : "this is a test"
}插入多条
// AddMore 插入多条
func AddMore() {
coll := DB.Collection("testdata")
docs := []interface{}{
bson.D{{"title", "Record of a Shriveled Datum"}, {"text", "No bytes, no problem. Just insert a document, in MongoDB"}},
bson.D{{"title", "Showcasing a Blossoming Binary"}, {"text", "Binary data, safely stored with GridFS. Bucket the data"}},
}
_, err := coll.InsertMany(context.TODO(), docs)
if err != nil {
panic(err)
}
}更新
更新单条
// UpdateOne 更新单条
func UpdateOne() {
coll := DB.Collection("testdata")
filter := bson.D{{"title", "test"}}
update := bson.D{{"$set", bson.D{{"avg_rating", 4.5}}}}
_, err := coll.UpdateOne(context.TODO(), filter, update)
if err != nil {
panic(err)
}
}UpdateOne有三个参数,传递一个context,一个过滤规则拿到匹配的数据,一个update表示将要更新的内容。
此处表示在testdata表中查询出title为test的这条数据,在匹配的这条记录中添加一个avg_rating的字段,其值为4.5。
更新多条
进行操作之前,我们先准备一些测试数据:
db.testdata.insert([
{ "name" : "小A", "identify": "aaa","age": 1, "group_identify": "ops"},
{ "name" : "小B", "identify": "bbb","age": 2, "group_identify": "ops"},
{ "name" : "小C", "identify": "ccc","age": 3, "group_identify": "ops"},
{ "name" : "小D", "identify": "ddd","age": 4, "group_identify": "test"},
{ "name" : "小E", "identify": "eee","age": 5, "group_identify": "test"},
{ "name" : "小F", "identify": "fff","age": 6, "group_identify": "test"}
])我的需求是更新test小组同学的年龄为当前的3倍:
// UpdateMany 更新多条
func UpdateMany() {
coll := DB.Collection("testdata")
filter := bson.D{{"group_identify", "test"}}
update := bson.D{{"$mul", bson.D{{"age", 3}}}}
_, err := coll.UpdateMany(context.TODO(), filter, update)
if err != nil {
panic(err)
}
}MongoDB在更新的时候,提供了一些很好用的方法供我们查询,详情参考:[[MongoDB交互时表达式与方法整理汇总#MongoDB中更新时的一些表达式]]
运行这个方法之后,可以看到这三个人的年龄更新了:
$ db.getCollection('testdata').find({"group_identify":"test"})
/* 1 */
{
"_id" : ObjectId("61f24699c8d32bc297dbecf2"),
"name" : "小D",
"identify" : "ddd",
"age" : 12.0,
"group_identify" : "test"
}
/* 2 */
{
"_id" : ObjectId("61f24699c8d32bc297dbecf3"),
"name" : "小E",
"identify" : "eee",
"age" : 15.0,
"group_identify" : "test"
}
/* 3 */
{
"_id" : ObjectId("61f24699c8d32bc297dbecf4"),
"name" : "小F",
"identify" : "fff",
"age" : 18.0,
"group_identify" : "test"
}查询
查询单条
// FindOne 查询单条
func FindOnd() {
var result bson.M
table := DB.Collection("testdata")
err := table.FindOne(context.TODO(), bson.M{"title": "test"}).Decode(&result) //
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("%v\n", result)
v, err := encoder.Encode(result, encoder.SortMapKeys)
if err != nil {
fmt.Printf("%v\n", err)
}
fmt.Println(string(v))
}利用ID查询
// FindOndAsId 基于ID查询单条
func FindOndAsId() {
var result bson.M
table := DB.Collection("user")
objid, err := primitive.ObjectIDFromHex("61f0f6d6c8d32bc297dbecd6")
if err != nil {
fmt.Printf("obj id failed: %v\n", err)
}
err = table.FindOne(context.TODO(), bson.M{"_id": objid}).Decode(&result)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("%v\n", result)
v, err := encoder.Encode(result, encoder.SortMapKeys)
if err != nil {
fmt.Printf("%v\n", err)
}
fmt.Println(string(v))
}模糊查询
type Article struct {
Title string
Text string
}
// FindAsLike 模糊查询
func FindAsLike() {
table := DB.Collection("testdata")
findOptions := options.Find()
filter := bson.D{}
filter = append(filter, bson.E{
Key: "title",
Value: bson.M{"$regex": primitive.Regex{Pattern: ".*" + "a" + ".*", Options: "i"}}}) //i 表示不区分大小写
cus, err := table.Find(ctx, filter, findOptions)
if err != nil {
fmt.Printf("find failed: %v\n", err)
}
defer func(cus *mongo.Cursor, ctx context.Context) {
err := cus.Close(ctx)
if err != nil {
return
}
}(cus, ctx)
list := make([]*Article, 0)
for cus.Next(ctx) {
article := new(Article)
err := cus.Decode(&article)
if err != nil {
fmt.Printf("decode failed: %v\n", err)
// return nil, tools.NewMongoError(err)
}
list = append(list, article)
}
fmt.Println("results: ", list)
for _, v := range list {
fmt.Println(v)
}
}查询多条
// FindMany 查询多条
func FindMany() {
/*
插入测试数据
db.testdata.insert([
{ "name" : "小A", "identify": "aaa","age":1},
{ "name" : "小B", "identify": "bbb","age":2},
{ "name" : "小C", "identify": "ccc","age":3},
{ "name" : "小D", "identify": "ddd","age":4},
{ "name" : "小E", "identify": "eee","age":5},
{ "name" : "小F", "identify": "fff","age":6},
])
*/
table := DB.Collection("testdata")
filter := bson.D{{"age", bson.D{{"$lte", 3}}}} // 查询年龄小于等于3的,这里特别有意思,能够使用$lte这种方法,类似这样的,MongoDB还提供了很多其他的查询方法,比如$gt等等
cursor, err := table.Find(ctx, filter)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
var results []bson.M
if err = cursor.All(context.TODO(), &results); err != nil {
panic(err)
}
for _, result := range results {
v, err := encoder.Encode(result, encoder.SortMapKeys)
if err != nil {
fmt.Printf("%v\n", err)
}
fmt.Println(string(v))
}
}就像更新的时候一样,查询的时候也有一些表达式可供使用。更多参考:[[MongoDB交互时表达式与方法整理汇总#mongodb中查询的表达式介绍]]
替换
替换单条
ReplaceOne() 您可以使用该方法替换集合中的文档。这个方法针对于cmdb场景更加合适。
首先添加一条测试数据:
db.testdata.insert([
{ "name" : "小A", "identify": "aaa","content":"this is aaa"},
])然后基于identify完全replace这条记录:
// ReplaceOne 替换单条
func ReplaceOne() {
coll := DB.Collection("testdata")
filter := bson.D{{"identify", "aaa"}}
replacement := bson.D{{"name", "小A-r"}, {"identify", "aaa"}, {"content", "this is aaa replace"}}
_, err := coll.ReplaceOne(context.TODO(), filter, replacement)
if err != nil {
panic(err)
}
}删除
删除单条
// DeleteOne 删除单条
func DeleteOne() {
coll := DB.Collection("testdata")
filter := bson.D{{"identify", "aaa"}}
_, err := coll.DeleteOne(context.TODO(), filter)
if err != nil {
panic(err)
}
}删除多条
同样,在删除的时候,我们调用Delete方法,传递过滤条件,这个时候也可以删除指定过滤的条件。
添加测试数据:
db.testdata.insert([
{ "name" : "小A", "identify": "aaa","age": 1, "group_identify": "ops"},
{ "name" : "小B", "identify": "bbb","age": 2, "group_identify": "ops"},
{ "name" : "小C", "identify": "ccc","age": 3, "group_identify": "ops"},
{ "name" : "小D", "identify": "ddd","age": 4, "group_identify": "test"},
{ "name" : "小E", "identify": "eee","age": 5, "group_identify": "test"},
{ "name" : "小F", "identify": "fff","age": 6, "group_identify": "test"}
])我们删除年龄大于3岁的记录:
// DeleteMany 删除多条
func DeleteMany() {
coll := DB.Collection("testdata")
filter := bson.D{{"age", bson.D{{"$gt", 3}}}}
_, err := coll.DeleteMany(context.TODO(), filter)
if err != nil {
panic(err)
}
}然后可以看到只剩下前三条了:
$ db.getCollection('testdata').find({})
/* 1 */
{
"_id" : ObjectId("61f24a4dc8d32bc297dbed02"),
"name" : "小A",
"identify" : "aaa",
"age" : 1.0,
"group_identify" : "ops"
}
/* 2 */
{
"_id" : ObjectId("61f24a4dc8d32bc297dbed03"),
"name" : "小B",
"identify" : "bbb",
"age" : 2.0,
"group_identify" : "ops"
}
/* 3 */
{
"_id" : ObjectId("61f24a4dc8d32bc297dbed04"),
"name" : "小C",
"identify" : "ccc",
"age" : 3.0,
"group_identify" : "ops"
}批量
BulkWrite()您可以使用该方法对集合执行批量写入操作 。
官方给的示例如下:
coll := DB.Collection("testdata")
models := []mongo.WriteModel{
mongo.NewReplaceOneModel().SetFilter(bson.D{{"title", "Record of a Shriveled Datum"}}).
SetReplacement(bson.D{{"title", "Dodging Greys"}, {"text", "When there're no matches, no longer need to panic. You can use upsert"}}),
mongo.NewUpdateOneModel().SetFilter(bson.D{{"title", "Dodging Greys"}}).
SetUpdate(bson.D{{"$set", bson.D{{"title", "Dodge The Greys"}}}}),
}
opts := options.BulkWrite().SetOrdered(true)
results, err := coll.BulkWrite(context.TODO(), models, opts)- 匹配一个文档,其中
title是“收缩基准的记录”并将其替换为新文档 - 匹配其中
title为“Dodging Greys”的文档并将该值更新为'Dodge The Greys'
通常不太会用到这种批量的方式。
汇总
两种方式
EstimatedDocumentCount():获得集合中文档数量的近似值CountDocuments():获得集合中文档的确切数量
// Count 查询数量
func Count() {
coll := DB.Collection("testdata")
filter := bson.D{{"group_identify", "test"}}
estCount, estCountErr := coll.EstimatedDocumentCount(context.TODO())
if estCountErr != nil {
panic(estCountErr)
}
count, err := coll.CountDocuments(context.TODO(), filter)
if err != nil {
panic(err)
}
fmt.Println(estCount, count)
}关联
关联查询
基于MongoDB原始语句的查询操作流程参考:[[MongoDB关联查询的学习以及实践]]
现在golang中使用如下方式实现关联查询:
func Aggregate() {
query := []bson.M{{
"$lookup": bson.M{
"from": "user",
"localField": "identify",
"foreignField": "groupIdentify",
"as": "output",
}}}
coll := DB.Collection("group")
cur, err := coll.Aggregate(context.TODO(), query)
if err != nil {
fmt.Printf("aggregate failed:%v\n", err)
}
defer cur.Close(context.TODO())
for cur.Next(context.TODO()) {
// 当数据没有映射到结构体时,可以通过map查询
one := make(map[string]interface{})
err := cur.Decode(&one)
if err != nil {
fmt.Printf("%v\n", err)
}
v, err := encoder.Encode(one, encoder.SortMapKeys)
if err != nil {
fmt.Printf("%v\n", err)
}
fmt.Println(string(v))
}
}运行结果如下:
$ go run main.go | jq
{
"_id": "61f0f6c2c8d32bc297dbecd2",
"identify": "yunweizu",
"name": "运维组",
"output": [
{
"_id": "61f0f6d6c8d32bc297dbecd4",
"groupIdentify": "yunweizu",
"identify": "aaa",
"name": "小A"
},
{
"_id": "61f0f6d6c8d32bc297dbecd5",
"groupIdentify": "yunweizu",
"identify": "bbb",
"name": "小B"
},
{
"_id": "61f0f6d6c8d32bc297dbecd6",
"groupIdentify": "yunweizu",
"identify": "ccc",
"name": "小C"
}
]
}
{
"_id": "61f0f6c2c8d32bc297dbecd3",
"identify": "kefuzu",
"name": "客服组",
"output": [
{
"_id": "61f0f6d6c8d32bc297dbecd7",
"groupIdentify": "kefuzu",
"identify": "ddd",
"name": "小D"
},
{
"_id": "61f0f6d6c8d32bc297dbecd8",
"groupIdentify": "kefuzu",
"identify": "eee",
"name": "小E"
},
{
"_id": "61f0f6d6c8d32bc297dbecd9",
"groupIdentify": "kefuzu",
"identify": "fff",
"name": "小F"
}
]
}如果想要过滤指定分组,则用如下方式:
func Aggregate() {
query := []bson.M{{
"$lookup": bson.M{
"from": "user",
"localField": "identify",
"foreignField": "groupIdentify",
"as": "output",
}},
{"$match": bson.M{"identify": "yunweizu"}},
}
coll := DB.Collection("group")
cur, err := coll.Aggregate(context.TODO(), query)
if err != nil {
fmt.Printf("aggregate failed:%v\n", err)
}
defer cur.Close(context.TODO())
for cur.Next(context.TODO()) {
// 当数据没有映射到结构体时,可以通过map查询
one := make(map[string]interface{})
err := cur.Decode(&one)
if err != nil {
fmt.Printf("%v\n", err)
}
v, err := encoder.Encode(one, encoder.SortMapKeys)
if err != nil {
fmt.Printf("%v\n", err)
}
fmt.Println(string(v))
}
}运行结果如下:
$ go run main.go | jq
{
"_id": "61f0f6c2c8d32bc297dbecd2",
"identify": "yunweizu",
"name": "运维组",
"output": [
{
"_id": "61f0f6d6c8d32bc297dbecd4",
"groupIdentify": "yunweizu",
"identify": "aaa",
"name": "小A"
},
{
"_id": "61f0f6d6c8d32bc297dbecd5",
"groupIdentify": "yunweizu",
"identify": "bbb",
"name": "小B"
},
{
"_id": "61f0f6d6c8d32bc297dbecd6",
"groupIdentify": "yunweizu",
"identify": "ccc",
"name": "小C"
}
]
}基本上和写原生语句差不多了。
字段
添加字段
添加单条
单个字段利用 $push指令进行添加:
// UpdateOneField 添加单个字段
func UpdateOneField() {
coll := DB.Collection("testdata")
objid, err := primitive.ObjectIDFromHex("62159551120b25bd2c801b09")
if err != nil {
fmt.Printf("%v\n", err)
}
filter := bson.M{"_id": objid}
updata := bson.M{"$push": bson.M{"link_data": bson.M{"field_identify": "1", "model_data_id": "5"}}}
_, err = coll.UpdateOne(ctx, filter, updata)
if err != nil {
panic(err)
}
}添加之后效果如下:
/* 1 */
{
"_id" : ObjectId("62159551120b25bd2c801b09"),
"title" : "Record of a Shriveled Datum",
"text" : "No bytes, no problem. Just insert a document, in MongoDB",
"link_data" : [
{
"field_identify" : "1",
"model_data_id" : "5"
},
}
]
}注意这里使用$push有一个问题就是,如果一个值重复往一个数组里添加,那么在MongoDB中会重复添加,效果如下:
$ db.getCollection('test').find({})
/* 1 */
{
"_id" : ObjectId("61ef6e9d78a349e08e8f50da"),
"test" : "test"
}
$ db.test.update({ "test" : "test" },{ $push: { label_list: "1" } })
再运行一次
$ db.test.update({ "test" : "test" },{ $push: { label_list: "1" } })
然后查询
$ db.getCollection('test').find({})
/* 1 */
{
"_id" : ObjectId("61ef6e9d78a349e08e8f50da"),
"test" : "test",
"label_list" : [
"1",
"1"
]
}此时可以改用addToSet,功效与push一致,只不过
$ db.getCollection('test').find({})
/* 1 */
{
"_id" : ObjectId("61ef6e9d78a349e08e8f50da"),
"test" : "test"
}
$ db.test.update({ "test" : "test" },{ $addToSet: { label_list: "1" } })
再运行一次
$ db.test.update({ "test" : "test" },{ $addToSet: { label_list: "1" } })
然后查询
$ db.getCollection('test').find({})
/* 1 */
{
"_id" : ObjectId("61ef6e9d78a349e08e8f50da"),
"test" : "test",
"label_list" : [
"1"
]
}可以看到这里虽然同样执行了两次,但是数据只会插入一次,适合那种进关联一次的场景。
添加多条
多个字段利用 push和each结合的方式进行添加,each允许我们添加一个数组的内容:
// UpdateOneField 添加单个字段数据
func UpdateOneField() {
coll := DB.Collection("testdata")
objid, err := primitive.ObjectIDFromHex("62159551120b25bd2c801b09")
if err != nil {
fmt.Printf("%v\n", err)
}
filter := bson.M{"_id": objid}
linkData := []map[string]string{
{
"field_identify": "eryajf_guanliandd",
"model_data_id": "6215aaf220ea934fb727096c",
},
{
"field_identify": "eryajf_guanliandd",
"model_data_id": "6215aaf220ea934fbaaaaaaa",
},
}
updata := bson.M{"$push": bson.M{"link_data": bson.M{"$each": linkData, "$position": 0}}}
_, err = coll.UpdateOne(ctx, filter, updata)
if err != nil {
panic(err)
}
}添加之后效果如下:
/* 1 */
{
"_id" : ObjectId("62159551120b25bd2c801b09"),
"title" : "Record of a Shriveled Datum",
"text" : "No bytes, no problem. Just insert a document, in MongoDB",
"link_data" : [
{
"field_identify" : "eryajf_guanliandd",
"model_data_id" : "6215aaf220ea934fb727096c"
},
{
"field_identify" : "eryajf_guanliandd",
"model_data_id" : "6215aaf220ea934fbaaaaaaa"
}
]
}同样,这里使用push存在一个问题,就是相同的数据,多次添加的时候,会多次存储,因此这里可以借助addToSet的能力,实现自动去重的效果。
关于push与addToSet的异同,详情可参考这篇:golang使用push和addToSet往数组添加字段的异同 (opens new window)
删除字段
删除单条
单个字段利用 $pull指令进行删除:
// DeleteOneField 删除单个字段数据
func DeleteOneField() {
coll := DB.Collection("testdata")
objid, err := primitive.ObjectIDFromHex("62159551120b25bd2c801b09")
if err != nil {
fmt.Printf("%v\n", err)
}
filter := bson.M{"_id": objid}
updata := bson.M{"$pull": bson.M{"link_data": bson.M{"field_identify": "1", "model_data_id": "5"}}}
_, err = coll.UpdateOne(ctx, filter, updata)
if err != nil {
panic(err)
}
}删除多条
删除多条记录利用$pullAll指令进行删除:
// DeleteManyField 删除多条记录
func DeleteManyField() {
coll := DB.Collection("testdata")
objid, err := primitive.ObjectIDFromHex("62159551120b25bd2c801b09")
if err != nil {
fmt.Printf("%v\n", err)
}
filter := bson.M{"_id": objid}
linkData := []map[string]string{
{
"field_identify": "eryajf_guanliandd",
"model_data_id": "6215aaf220ea934fb727096c",
},
{
"field_identify": "eryajf_guanliandd",
"model_data_id": "6215aaf220ea934fbaaaaaaa",
},
}
updata := bson.M{"$pullAll": bson.M{"link_data_testa": linkData}}
_, err = coll.UpdateOne(ctx, filter, updata)
if err != nil {
panic(err)
}
}边栏推荐
- Guitar Pro tutorial how to set up a MIDI keyboard
- Implementation of asynchronous query of Flink dimension table and troubleshooting
- 借助SpotBugs将程序错误扼杀在摇篮中
- 山东大学软件学院项目实训-创新实训-山大软院网络攻防靶场实验平台(二十五)-项目个人总结
- R language uses ggplot2 to visualize the density graph (curve) of specific data columns in dataframe data, and uses Xlim parameter to specify the range of X axis
- Yyds dry goods inventory leetcode question set 911 - 920
- Atlassian Confluence 远程代码执行漏洞(CVE-2022-26134)漏洞复现
- MySQL transaction introduction and transaction isolation level
- Introduction to several common functions of fiddler packet capturing (stop packet capturing, clear session window contents, filter requests, decode, set breakpoints...)
- Notes on user experience elements: user centered product design
猜你喜欢

记录使用yolov5进行旋转目标的检测

Some minor problems and solutions encountered when using ubantu

Risc-v ide mounriver studio v1.60 update point introduction

How to view, modify, and delete SSH

Modify the configuration of the router connected to your computer. The website is 192.168.1.1
![[CSP]202012-2期末预测之最佳阈值](/img/40/9b59bd692bcfe05d16614cc6d55d1f.png)
[CSP]202012-2期末预测之最佳阈值

Arm64 stack backtracking

Deep interest evolution network for click through rate prediction

Cicada mother talks to rainbow couple: 1.3 billion goods a year, from e-commerce beginners to super goods anchor

Exclusive interview with oppo find X5 Product Manager: deeply cultivate self-developed chips to create the ultimate flagship experience with the highest standards
随机推荐
R语言计算data.table在一个分组变量的值固定的情况下另外一个分组变量下指定数值变量的均值
566. 重塑矩阵
R语言使用epiDisplay包的tabpct函数生成二维列联表并使用马赛克图可视化列联表(二维列联表、边际频数、以及按行、按列的比例)、自定义设置cex.axis参数改变轴标签数值的大小
Deep interest evolution network for click through rate prediction
内核中断整体流程图
MySQL transaction introduction and transaction isolation level
卖疯了的临期产品:超低价、大混战与新希望
Two ways of tensorflow2 training data sets
406. 根据身高重建队列
"Upgrade strategy" of two new committers
Where is it safer to open an account for thermal coal futures? How much is the thermal coal futures deposit?
R language uses ggplot2 to visualize the density graph (curve) of specific data columns in dataframe data, and uses Xlim parameter to specify the range of X axis
写技术博客的意义
R语言使用ggplot2可视化dataframe数据中特定数据列的密度图(曲线)、并使用xlim参数指定X轴的范围
Tidb Hackathon 2021 - pcloud: conduct icloud pcloud team interview on the database
First acquaintance with go language
(6) Control statement if/else switch
错误记录:IllegalStateException: Optional int parameter ‘xxxx‘ is
力扣今日题926. 将字符串翻转到单调递增
TensorFlow从网络读取数据