连接
首先得在admin数据库中创建角色
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func GetMongo() (*mongo.Database, error) {
credential := options.Credential{
AuthMechanism: "SCRAM-SHA-256",
Username: "admin",
Password: "123456",
AuthSource: "admin",
}
clientOpts := options.Client().ApplyURI(fmt.Sprintf("mongodb://%s:%d", "127.0.0.1", 27017)).SetAuth(credential)
var ctx = context.TODO()
client, err := mongo.Connect(ctx, clientOpts)
if err != nil {
return nil, err
}
// Check the connection
err = client.Ping(ctx, nil)
if err != nil {
return nil, err
}
mongodb := client.Database("test")
return mongodb, nil
}
}
插入数据
添加数据:
package test
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
)
type Add1 struct {
Id int
Text string
}
func (a1 *Add1) Add(mongo *mongo.Database, ctx context.Context) error {
result, err := mongo.Collection("test").InsertOne(ctx, a1)
fmt.Println(result.InsertedID)
return err
}
type Add2 struct {
Id int
TextList []string
}
func (a2 *Add2) Add(mongo *mongo.Database, ctx context.Context) error {
result, err := mongo.Collection("test").InsertOne(ctx, a2)
fmt.Println(result.InsertedID)
return err
}
type Add3 struct {
Id int
Add1List []Add1
}
func (a3 *Add3) Add(mongo *mongo.Database, ctx context.Context) error {
result, err := mongo.Collection("test").InsertOne(ctx, a3)
fmt.Println(result.InsertedID)
return err
}
// 插入多条数据
func AddMany(mongo *mongo.Database, ctx context.Context, data ...interface{}) error {
result, err := mongo.Collection("test").InsertMany(ctx, data)
fmt.Println(result.InsertedIDs...)
return err
}
调用方法:
package main
import (
"context"
"fmt"
"src/test"
)
func main() {
mongo, _ := test.GetMongo()
ctx := context.TODO()
add1 := test.Add1{Id: 1, Text: "hello world"}
add1.Add(mongo, ctx)
add2 := test.Add2{Id: 2, TextList: []string{"hello1", "hello2", "hello3"}}
add2.Add(mongo, ctx)
temp1 := test.Add1{Id: 1, Text: "hello1"}
temp2 := test.Add1{Id: 2, Text: "hello2"}
temp3 := test.Add1{Id: 3, Text: "hello3"}
temp4 := test.Add1{Id: 4, Text: "hello4"}
temp5 := test.Add1{Id: 5, Text: "hello5"}
add3_1 := test.Add3{Id: 3, Add1List: []test.Add1{temp1, temp2, temp3}}
add3_2 := test.Add3{Id: 4, Add1List: []test.Add1{temp1, temp2, temp3, temp4}}
add3_3 := test.Add3{Id: 5, Add1List: []test.Add1{temp1, temp2, temp3, temp4, temp5}}
test.AddMany(mongo, ctx, add3_1, add3_2, add3_3)
}
使用 studio 3T for mongoDB 查看:
可以看到,数据正常插入了(注意看,我们的字段是大写字母开头,保存到mongodb就变成小写了,这是默认转换的,多数数据库都是这么处理的)
PS:数据库"test"和集合“test”我都没有提前创建,如果没有的话,它会自动创建
查询数据
简单查询
查询方法
package test
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// 查询全部
func FindAll(mongo *mongo.Database, ctx context.Context) error {
cur, err := mongo.Collection("test").Find(ctx, bson.M{}) // 查询所有就是bson.M{},没有任何条件
// 遍历数据
for cur.TryNext(ctx) {
result, _ := cur.Current.Elements()
fmt.Println(result)
}
return err
}
// 每天单独查询,并且解析成对应的结构体
func FindAdd(mongo *mongo.Database, ctx context.Context) {
// 查询Add3
result3 := Add3{}
findFilter3 := bson.M{"id": 3}
mongo.Collection("test").FindOne(ctx, findFilter3).Decode(&result3)
fmt.Println("add3:", result3)
}
调用方法:
// 查询数据
func main() {
mongo, err := test.GetMongo()
fmt.Println(err)
ctx := context.TODO()
test.FindAll(mongo, ctx)
test.FindAdd(mongo, ctx)
}
结果:
[{"_id":{"$oid":"629327481df85fd689e8273b"}} {"id":{"$numberInt":"1"}} {"text":"hello world"}]
[{"_id":{"$oid":"629327481df85fd689e8273c"}} {"id":{"$numberInt":"2"}} {"textlist":["hello1","hello2","hello3"]}]
[{"_id":{"$oid":"629327481df85fd689e8273d"}} {"id":{"$numberInt":"3"}} {"add1list":[{"id":{"$numberInt":"1"},"text":"hello1"},{"id":{"$numberInt":"2"},"text":"hello2"},{"id":{"$numberInt":"3"},"text":"hello3"}]}]
[{"_id":{"$oid":"629327481df85fd689e8273e"}} {"id":{"$numberInt":"4"}} {"add1list":[{"id":{"$numberInt":"1"},"text":"hello1"},{"id":{"$numberInt":"2"},"text":"hello2"},{"id":{"$numberInt":"3"},"text":"hello3"},{"id":{"$numberInt":"4"},"text":"hello4"}]}]
[{"_id":{"$oid":"629327481df85fd689e8273f"}} {"id":{"$numberInt":"5"}} {"add1list":[{"id":{"$numberInt":"1"},"text":"hello1"},{"id":{"$numberInt":"2"},"text":"hello2"},{"id":{"$numberInt":"3"},"text":"hello3"},{"id":{"$numberInt":"4"},"text":"hello4"},{"id":{"$numberInt":"5"},"text":"hello5"}]}]
add3: {3 [{1 hello1} {2 hello2} {3 hello3}]}
看吧,这种查询还是挺方便的,能直接转换成对应的结构体,bson.M{"id": 1}
就是查询id等于1的数据。
查询指定字段
// 查询某个具体的字段
func FindField(mongo *mongo.Database, ctx context.Context) {
// 下面的查询相当于 SELECT add1list from test WHERE id = 3
projection1 := bson.D{{"add1list", 1}, {"_id", 0}} // 查询指定字段add1List,排除字段“_id”.1表示选择,设置为0表示排除
findFilter1 := bson.M{"id": 3} // 查询条件
temp1 := mongo.Collection("test").FindOne(ctx, findFilter1, options.FindOne().SetProjection(projection1))
rawByte, _ := temp1.DecodeBytes()
rawS := rawByte.String()
fmt.Println("rawS:", rawS)
add3 := Add3{}
temp1.Decode(&add3) // 解析
fmt.Println("add3:", add3)
// 下面的查询仅返回数组里的text字段
projection2 := bson.D{{"add1list.text", 1}, {"_id", 0}} // 查询指定字段add1List,排除字段“_id”.1表示选择,设置为0表示排除
// projection2 := bson.M{"add1list.text": 1, "_id": 0} // 这种方式也行
// projection2 := bson.M{"add1list": bson.M{"text": 1}, "_id": 0} // 这种方式也行
findFilter2 := bson.M{"id": 3} // 查询条件
temp2 := mongo.Collection("test").FindOne(ctx, findFilter2, options.FindOne().SetProjection(projection2))
rawByte, _ = temp2.DecodeBytes()
rawV, _ := rawByte.Values()
fmt.Println("rawV:", rawV[0])
add3_1 := Add3{}
temp2.Decode(&add3_1) // 解析
fmt.Println("add3_1:", add3_1)
// 下面查询数组中完全匹配的文档
projection3 := bson.M{"add1list": 1, "_id": 0} // 查询指定字段add1List,排除字段“_id” 1表示选择,设置为0表示排除
findFilter3 := bson.M{"add1list": bson.M{"id": 4, "text": "hello4"}} // 此处的查询条件需要完全匹配才行
temp3 := mongo.Collection("test").FindOne(ctx, findFilter3, options.FindOne().SetProjection(projection3))
add3_2 := Add3{}
temp3.Decode(&add3_2) // 解析
fmt.Println("add3_2:", add3_2)
// 下面查询数组中满足一定条件的文档
projection4 := bson.M{"add1list": 1, "_id": 0} // 查询指定字段add1List,排除字段“_id” 1表示选择,设置为0表示排除
findFilter4 := bson.M{"add1list.text": "hello5"} // 此处查询text等于hello5的文档
temp4 := mongo.Collection("test").FindOne(ctx, findFilter4, options.FindOne().SetProjection(projection4))
add3_3 := Add3{}
temp4.Decode(&add3_3) // 解析
fmt.Println("add3_3:", add3_3)
}
rawS: {"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"}]}
add3: {0 [{1 hello1} {2 hello2} {3 hello3}]}
rawV: [{"text": "hello1"},{"text": "hello2"},{"text": "hello3"}]
add3_1: {0 [{0 hello1} {0 hello2} {0 hello3}]}
add3_2: {0 [{1 hello1} {2 hello2} {3 hello3} {4 hello4}]}
add3_3: {0 [{1 hello1} {2 hello2} {3 hello3} {4 hello4} {5 hello5}]}
上面的例子演示的根据条件查询数据,并且可以指定返回的字段,但是:
- 无法仅返回值,字段的名字和值会一起别返回
- document是最小的返回单位,查询到满足条件的文档后,会将整条文档返回
其他关键字查询
// 其他条件查询,见:https://www.mongodb.com/docs/manual/reference/operator/query/
func Find(mongo *mongo.Database, ctx context.Context) {
// 下面的查询相当于 SELECT id from test WHERE id > 2
projection := bson.M{"_id": 0}
findFilter1 := bson.M{"id": bson.M{"$gt": 2}} // 查询条件 gt是大于,gte是大于等于
temp1, _ := mongo.Collection("test").Find(ctx, findFilter1, options.Find().SetProjection(projection))
// 遍历数据
for temp1.TryNext(ctx) {
result := temp1.Current.Lookup("id")
fmt.Println(result)
}
fmt.Println("1~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 下面的查询相当于 SELECT id from test WHERE id <= 3
findFilter2 := bson.M{"id": bson.M{"$lte": 3}} // 查询条件 lt是小于,lte是小于等于
temp2, _ := mongo.Collection("test").Find(ctx, findFilter2, options.Find().SetProjection(projection))
// 遍历数据
for temp2.TryNext(ctx) {
result := temp2.Current.Index(0)
fmt.Println(result)
}
fmt.Println("2~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 查询不包含add1list字段的文档
findFilter3 := bson.M{"add1list": nil} // 查询条件
temp3, _ := mongo.Collection("test").Find(ctx, findFilter3, options.Find().SetProjection(projection))
// 遍历数据
for temp3.TryNext(ctx) {
result := temp3.Current.String()
fmt.Println(result)
}
fmt.Println("3~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 查询存在add1list字段的文档
findFilter4 := bson.M{"add1list": bson.M{"$exists": true}} // 查询条件
temp4, _ := mongo.Collection("test").Find(ctx, findFilter4, options.Find().SetProjection(projection))
// 遍历数据
for temp4.TryNext(ctx) {
result := temp4.Current.String()
fmt.Println(result)
}
fmt.Println("4~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 查询add1list是array类型的文档,类型见:https://www.mongodb.com/docs/manual/reference/bson-types/
findFilter5 := bson.M{"add1list": bson.M{"$type": 4}} // 类别编号,4表示array
temp5, _ := mongo.Collection("test").Find(ctx, findFilter5, options.Find().SetProjection(projection))
// 遍历数据
for temp5.TryNext(ctx) {
result := temp5.Current.String()
fmt.Println(result)
}
fmt.Println("5~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 查询add1list长度为3的文档
findFilter6 := bson.M{"add1list": bson.M{"$size": 3}} // 类别编号,4表示array
temp6, _ := mongo.Collection("test").Find(ctx, findFilter6, options.Find().SetProjection(projection))
// 遍历数据
for temp6.TryNext(ctx) {
result := temp6.Current.String()
fmt.Println(result)
}
fmt.Println("6~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 指定多个条件查询,$elemMatch仅数组类型可用,以下查询add1list中有某个元素的id同时满足大于4且小于5,显然没有这样的元素
findFilter7 := bson.M{"add1list": bson.M{"$elemMatch": bson.M{"id": bson.M{"$gt": 4, "$lt": 5}}}}
temp7, _ := mongo.Collection("test").Find(ctx, findFilter7, options.Find().SetProjection(projection))
// 遍历数据
for temp7.TryNext(ctx) {
result := temp7.Current.String()
fmt.Println(result)
}
fmt.Println("7~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 和上面形成对比,下面的查询是add1list中存在元素的id大于4,且存在元素的id小于5.可以不是同一个元素,和上面对比,区别就是上面必须是同一个元素满足所有条件
findFilter8 := bson.M{"add1list.id": bson.M{"$gt": 4, "$lt": 5}}
temp8, _ := mongo.Collection("test").Find(ctx, findFilter8, options.Find().SetProjection(projection))
// 遍历数据
for temp8.TryNext(ctx) {
result := temp8.Current.String()
fmt.Println(result)
}
fmt.Println("8~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 查询数组中包含的id的文档
findFilter9 := bson.M{"add1list.id": bson.M{"$in": bson.A{4}}}
temp9, _ := mongo.Collection("test").Find(ctx, findFilter9, options.Find().SetProjection(projection))
// 遍历数据
for temp9.TryNext(ctx) {
result := temp9.Current.String()
fmt.Println(result)
}
fmt.Println("9~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 正则匹配:"$options": "i"表示不区分大小写。"$nin": bson.A{"hello5"}表示text不能等于数组里的值,详见:https://www.mongodb.com/docs/manual/reference/operator/query/regex/
findFilter10 := bson.M{"add1list.text": bson.M{"$regex": "Hello*", "$options": "i", "$nin": bson.A{"hello5"}}}
temp10, _ := mongo.Collection("test").Find(ctx, findFilter10, options.Find().SetProjection(projection))
// 遍历数据
for temp10.TryNext(ctx) {
result := temp10.Current.String()
fmt.Println(result)
}
fmt.Println("10~~~~~~~~~~~~~~~~~~~~~~~~~~")
}
结果:
{"$numberInt":"3"}
{"$numberInt":"4"}
{"$numberInt":"5"}
1~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id":{"$numberInt":"1"}}
{"id":{"$numberInt":"2"}}
{"id":{"$numberInt":"3"}}
2~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"1"},"text": "hello world"}
{"id": {"$numberInt":"2"},"textlist": ["hello1","hello2","hello3"]}
3~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"3"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"}]}
{"id": {"$numberInt":"4"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"}]}
{"id": {"$numberInt":"5"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"},{"id": {"$numberInt":"5"},"text": "hello5"}]}
4~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"3"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"}]}
{"id": {"$numberInt":"4"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"}]}
{"id": {"$numberInt":"5"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"},{"id": {"$numberInt":"5"},"text": "hello5"}]}
5~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"3"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"}]}
6~~~~~~~~~~~~~~~~~~~~~~~~~~
7~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"5"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"},{"id": {"$numberInt":"5"},"text": "hello5"}]}
8~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"4"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"}]}
{"id": {"$numberInt":"5"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"},{"id": {"$numberInt":"5"},"text": "hello5"}]}
9~~~~~~~~~~~~~~~~~~~~~~~~~~
{"id": {"$numberInt":"3"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"}]}
{"id": {"$numberInt":"4"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "hello3"},{"id": {"$numberInt":"4"},"text": "hello4"}]}
10~~~~~~~~~~~~~~~~~~~~~~~~~~
列举了一下查询的方式,官方还有很多很复杂的查询,具体去查看官方文档。
修改
接口实现
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func Update(mongo *mongo.Database, ctx context.Context) {
// 更新id
findFilter1 := bson.M{"add1list.text": "hello3"}
updateFilter1 := bson.M{"$set": bson.M{"id": 10}}
result1, _ := mongo.Collection("test").UpdateOne(ctx, findFilter1, updateFilter1)
fmt.Println(result1.MatchedCount, result1.ModifiedCount)
fmt.Println("1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
// 更新指定字段,详见:https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/#mongodb-update-up.---identifier--
findFilter2 := bson.M{"add1list.text": "hello3"} // 确保后续修改的文档具有add1list.text字段
updateFilter2 := bson.M{"$set": bson.M{"add1list.$[elem].text": "helloUpdate"}} // 将指定字段的内容更新
arrayFilters1 := options.ArrayFilters{Filters: bson.A{bson.M{"elem.text": "hello3"}}} // 设置条件匹配想要的字段,elem就变成后面的占位符,数组的下标
mongo.Collection("test").UpdateMany(ctx, findFilter2, updateFilter2, options.Update().SetArrayFilters(arrayFilters1))
findFilter3 := bson.M{"add1list.text": "helloUpdate"}
// 验证结果
cur, _ := mongo.Collection("test").Find(ctx, findFilter3)
// 遍历数据
for cur.TryNext(ctx) {
result := cur.Current.String()
fmt.Println(result)
}
fmt.Println("2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
}
修改也很多门道,做了些简单的演示,第二个例子也算是把基本功能都包含了,可以以此类推,输出如下:
1 1
1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{"_id": {"$oid":"62937de4e2d54e0af9728905"},"id": {"$numberInt":"10"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "helloUpdate"}]}
{"_id": {"$oid":"62937de4e2d54e0af9728906"},"id": {"$numberInt":"4"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "helloUpdate"},{"id": {"$numberInt":"4"},"text": "hello4"}]}
{"_id": {"$oid":"62937de4e2d54e0af9728907"},"id": {"$numberInt":"5"},"add1list": [{"id": {"$numberInt":"1"},"text": "hello1"},{"id": {"$numberInt":"2"},"text": "hello2"},{"id": {"$numberInt":"3"},"text": "helloUpdate"},{"id": {"$numberInt":"4"},"text": "hello4"},{"id": {"$numberInt":"5"},"text": "hello5"}]}
2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
删除
删除就最简单了,没啥新的东西,就是跟查询时一样的条件,根据条件查询:
func Del(mongo *mongo.Database, ctx context.Context) {
// 删除一条
findFilter := bson.M{"id": 3}
result, _ := mongo.Collection("test").DeleteOne(ctx, findFilter)
fmt.Println(result.DeletedCount)
// 删除多条记录
findFilter2 := bson.M{"add1list.text": "hello3"}
result, _ = mongo.Collection("test").DeleteMany(ctx, findFilter2)
fmt.Println(result.DeletedCount)
// 删除全部
result, _ = mongo.Collection("test").DeleteMany(ctx, bson.M{})
fmt.Println(result.DeletedCount)
}
M,D,E,A
首先,我们得知道,mongo的数据是json形式的,但是在json的基础上,它丰富了数据类型,所以叫做了bson。这是最基本的数据结构。
上面的代码大量用到bson.M
,看了代码下来应该能理解了,其实就是构造了类似于map的东西,用于封装成mongo理解的数据。但是我们多数使用了M,实际上还有几个,他们的作用和区别:
M
是一个无序的bson对象。用法也和map很像。在数据对顺序不敏感的时候,优先使用它。
D
有序的bson对象,和M的本质区别就是对顺序敏感。用法稍有不同,M用冒号,它用逗号,用它比较烦,大括号很多层。不过也是有必要的。
A
有序的bson数组,当需要数组时,它作为容器去包围M和D。
E
不怎么用,官方都说用D代替使用,所以不需要了解吧。
总结
上面代码基本把使用mongo-driver的思路演示清楚了,虽然api还有很多细节,但是可以根据官方文档自己去推演了。按需学习嘛。
然后就是去查mongodb在shell上有什么操作,基本上go上也能实现,只不过使用上有点不同。
演示代码完整版地址:https://gitee.com/lsjWeiYi/mongo