mongodb学习笔记(2)go语言操作mongodb
1、安装驱动包
1.1安装mongoDB Go驱动包
1 | go get github.com/mongodb/mongo- go -driverl |
1.2通过go连接MongoDB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package main import ( "context" "fmt" "log" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main() { // 设置客户端连接配置 clientOptions := options.Client().ApplyURI( "mongodb://127.0.0.1:27017" ) // 连接到MongoDB Client, err := mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatal(err) } defer func (){ // 断开连接 err = Client.Disconnect(context.TODO()) if err != nil { log.Fatal(err) } fmt.Println( "Connection to MongoDB closed." ) }() // 检查连接 err = Client.Ping(context.TODO(), nil) if err != nil { log.Fatal(err) } fmt.Println( "Connected to MongoDB!" ) } |
1.3连接池模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import ( "context" "time" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func ConnectToDB(uri, name string, timeout time.Duration, num uint64) (*mongo.Database, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() o := options.Client().ApplyURI(uri) o.SetMaxPoolSize(num) client, err := mongo.Connect(ctx, o) if err != nil { return nil, err } return client.Database(name), nil } |
2、BSON
2.1概述
MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON)的二进制表示中。与其他将JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易可靠地处理、排序和比较数据。
连接MongoDB的Go驱动程序中有两大类型表示BSON数据:D
和Raw
。
类型D
家族被用来简洁地构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用。D
家族包括四类:
-
- D:一个BSON文档。这种类型应该在顺序重要的情况下使用,比如MongoDB命令。
- M:一张无序的map。它和D是一样的,只是它不保持顺序。
- A:一个BSON数组。
- E:D里面的一个元素。
2.2导入包
要使用BSON,需要先导入下面的包:
1 | import "go.mongodb.org/mongo-driver/bson" |
3、CRUD
3.1概述
下面以user和video这两个结构体来演示mongodb的CRUD,它们的结构如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | type User struct { UserId int64 `bson: "user_id" ` Username string `bson: "username" ` FollowCount int64 `bson: "follow_count" ` // 关注数 FollowerCount int64 `bson: "follower_count" ` // 粉丝数 Follows []int64 `bson: "follows" ` // 关注列表 Followers []int64 `bson: "followers" ` // 粉丝列表 PublishList []int64 `bson: "publish_list" ` // 发布视频列表 FavoriteList []int64 `bson: "favorite_list" ` // 点赞列表 } type Video struct { VideoId int64 `bson: "video_id" ` UserId int64 `bson: "user_id" ` PlayUrl string `bson: "play_url" ` CoverUrl string `bson: "cover_url" ` FavoriteCount int64 `bson: "favorite_count" ` Favorites []int64 `bson: "favorites" ` CommentCount int64 `bson: "comment_count" ` Comments []Comment `bson: "comments, inline" ` PublishDate time.Time `bson: "publish_date" ` Title string `bson: "title" ` } |
3.2插入元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | //插入单个数据 func InsertOneVideo(Client *mongo.Client){ coll := Client.Database( "tiktok" ).Collection( "video" ) video:=Video{ VideoId: 10, UserId: 1, PlayUrl: "https://www.w3schools.com/html/movie.mp4" , CoverUrl: "https://cdn.pixabay.com/photo/2016/03/27/18/10/bear-1283347_1280.jpg" , FavoriteCount: 0, CommentCount: 0, Favorites: []int64{}, Comments: []Comment{}, PublishDate: time.Now(), Title: "video10" , } result, err := coll.InsertOne(context.TODO(), video) if err != nil { fmt.Println(err) } fmt.Println(result) } //插入多个数据 func InsertVideos(Client *mongo.Client){ t := time.Now() var vs [] interface {} for i:=0;i<10;i++{ mm, _ := time.ParseDuration(strconv.Itoa(i*60)+ "m" ) video:=Video{ VideoId: int64(i), UserId: int64(i), PlayUrl: "https://www.w3schools.com/html/movie.mp4" , CoverUrl: "https://cdn.pixabay.com/photo/2016/03/27/18/10/bear-1283347_1280.jpg" , FavoriteCount: 0, CommentCount: 0, Favorites: []int64{}, Comments: []Comment{}, PublishDate: t.Add(mm), Title: "video" +strconv.Itoa(i), } vs=append(vs,video) } collection := Client.Database( "tiktok" ).Collection( "video" ) insertManyResult, err := collection.InsertMany(context.TODO(), vs) if err != nil { log.Fatal(err) } fmt.Println( "Inserted multiple documents: " , insertManyResult.InsertedIDs) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | //查询到匹配数据则修改,否则就插入 func UpdateOrInsert(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "username" , "Amy" }} update := bson.D{{ "$set" , bson.D{{ "username" , Susan}}}} opts := options.Update().SetUpsert(true) result, err := coll.UpdateOne(context.TODO(), filter, update, opts) if err != nil { panic(err) } fmt.Printf( "Number of documents updated: %v\n" , result.ModifiedCount) fmt.Printf( "Number of documents upserted: %v\n" , result.UpsertedCount) } |
3.3删除元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //删除一条文档 func DeleteOneVideo(Client *mongo.Client){ coll := Client.Database( "tiktok" ).Collection( "video" ) filter := bson.D{{ "VideoId" , "10" }} result, err := coll.DeleteOne(context.TODO(), filter) if err != nil { panic(err) } fmt.Println(result) } //删除多条文档 func DeleteVideos(Client *mongo.Client){ coll := Client.Database( "tiktok" ).Collection( "video" ) filter := bson.D{{ "VideoId" , bson.D{{ "$gt" , 9}}}} results, err := coll.DeleteMany(context.TODO(), filter) if err != nil { panic(err) } fmt.Println(results) } |
3.4更新文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //更新多条文档 func UpdateManyUsers(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "UserId" , bson.D{{ "$gt" , 5}}}} update := bson.D{{ "$mul" , bson.D{{ "FollowCount" , 1}}}} result, err := coll.UpdateMany(context.TODO(), filter, update) if err != nil { panic(err) } fmt.Println(result) } //查询到匹配数据则修改,否则就插入 func UpdateOrInsert(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "username" , "Amy" }} update := bson.D{{ "$set" , bson.D{{ "username" , Susan}}}} opts := options.Update().SetUpsert(true) result, err := coll.UpdateOne(context.TODO(), filter, update, opts) if err != nil { panic(err) } fmt.Printf( "Number of documents updated: %v\n" , result.ModifiedCount) fmt.Printf( "Number of documents upserted: %v\n" , result.UpsertedCount) } |
1 2 3 4 5 6 7 8 9 10 11 12 | //替换文档 func ReplaceVideo(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "user_id" , 10}} replacement := bson.D{{ "user_id" , "10" }, { "username" , "david" }} result, err := coll.ReplaceOne(context.TODO(), filter, replacement) if err!=nil{ panic(err) } fmt.Printf( "Documents matched: %v\n" , result.MatchedCount) fmt.Printf( "Documents replaced: %v\n" , result.ModifiedCount) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | //向数组添加元素 func Add(client *mongo.Client, id, videoId int64){ collection := client.Database( "tiktok" ).Collection( "user" ) query := bson.M{ "user_id" : id} update := bson.M{ "$push" : bson.M{ "favorite_list" : videoId}} result, err := collection.UpdateOne(context.TODO(), query, update) if err != nil { panic(err) } fmt.Println( "更新用户信息的结果" ,result) collection = client.Database( "tiktok" ).Collection( "video" ) //更新点赞列表 query = bson.M{ "video_id" : videoId} update = bson.M{ "$push" : bson.M{ "favorites" : id}} result, err = collection.UpdateOne(context.TODO(), query, update) if err != nil { panic(err) } fmt.Println( "更新用户信息的结果" ,result) } //从数组删除指定元素 func Reduce(client *mongo.Client, id, videoId int64){ collection := client.Database( "tiktok" ).Collection( "user" ) query := bson.M{ "user_id" : id} update := bson.M{ "$pull" : bson.M{ "favorite_list" : videoId}} result, err := collection.UpdateOne(context.TODO(), query, update) if err != nil { panic(err) } fmt.Println( "更新用户信息的结果" ,result) collection = client.Database( "tiktok" ).Collection( "video" ) //更新点赞列表 query = bson.M{ "video_id" : videoId} update = bson.M{ "$pull" : bson.M{ "favorites" : id}} result, err = collection.UpdateOne(context.TODO(), query, update) if err != nil { panic(err) } fmt.Println( "更新用户信息的结果" ,result) } |
3.5查询文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | //查询的单个文档 func QueryUserByID(client *mongo.Client, id int64) User { collection := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "user_id" , id}} var result User err := collection.FindOne(context.TODO(), filter).Decode(&result) if err != nil { log.Println(err) } fmt.Printf( "根据Id查询用户的结果: %+v\n" , result) return result } //查询多个文档 func QueryVideosByTime(Client *mongo.Client, t time.Time)([]*Video, error){ // 将选项传递给Find() findOptions := options.Find() findOptions.SetLimit(30) //设置一次查询的最大数量 // 把bson.D{{}}作为一个filter来匹配所有文档 collection := Client.Database( "tiktok" ).Collection( "video" ) sort := bson.D{{ "publish_date" , -1}} findOptions.SetSort(sort) cur, err := collection.Find(context.TODO(), bson.M{ "publish_date" : bson.M{ "$gte" : t}}, findOptions) if err != nil { log.Fatal(err) return results,err } // 查找多个文档返回一个光标 // 遍历游标允许我们一次解码一个文档 for cur.Next(context.TODO()) { // 创建一个值,将单个文档解码为该值 var elem Video err := cur.Decode(&elem) if err != nil { log.Fatal(err) return results,err } results = append(results, &elem) } if err := cur.Err(); err != nil { log.Fatal(err) return results,err } // 完成后关闭游标 cur.Close(context.TODO()) //fmt.Printf("Found multiple documents (array of pointers): %#v,%d\n", results,len(results)) for i:=0;i<len(results);i++{ fmt.Println(results[i].PublishDate) } return results,err } |
4、批量操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //批量操作 func Bulk(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) models := []mongo.WriteModel{ mongo.NewInsertOneModel().SetDocument(bson.D{{ "user_id" , "11" }, { "username" , "jack11" }}), mongo.NewInsertOneModel().SetDocument(bson.D{{ "user_id" , "12" }, { "username" , "jack12" }}), mongo.NewReplaceOneModel().SetFilter(bson.D{{ "user_id" , "11" }}). SetReplacement(bson.D{{ "user_id" , 11},{ "username" , "Amy" }}), mongo.NewUpdateManyModel().SetFilter(bson.D{{ "user_id" , bson.D{{ "$lt" , 7}}}}). SetUpdate(bson.D{{ "$inc" , bson.D{{ "follows" , 3}}}}), mongo.NewDeleteManyModel().SetFilter(bson.D{{ "follows" , 9}}), } opts := options.BulkWrite().SetOrdered(false) //设置插入的顺序是否按照models的顺序 results, err := coll.BulkWrite(context.TODO(), models, opts) if err != nil { panic(err) } fmt.Printf( "Number of documents inserted: %d\n" , results.InsertedCount) fmt.Printf( "Number of documents replaced or updated: %d\n" , results.ModifiedCount) fmt.Printf( "Number of documents deleted: %d\n" , results.DeletedCount) } |
5、复合操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //复合操作:查找和删除 func FindAndDelete(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "user_id" , 11}} var deletedDoc bson.D err := coll.FindOneAndDelete(context.TODO(), filter).Decode(&deletedDoc) if err != nil { panic(err) } fmt.Println(deletedDoc) } //复合操作:查找和更新 func FindAndUpdate(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "user_id" , 12}} update := bson.D{{ "$set" , bson.D{{ "followers" , 9}}}} opts := options.FindOneAndUpdate().SetReturnDocument(options.After) var updatedDoc bson.D err := coll.FindOneAndUpdate(context.TODO(), filter, update, opts).Decode(&updatedDoc) if err != nil { panic(err) } fmt.Println(updatedDoc) } //复合操作:查找和替换 func FindAndReplace(client *mongo.Client){ coll := client.Database( "tiktok" ).Collection( "user" ) filter := bson.D{{ "user_id" , 12}} replacement := bson.D{{ "user_id" , 12}, { "username" , "bomb" }} var previousDoc bson.D err := coll.FindOneAndReplace(context.TODO(), filter, replacement).Decode(&previousDoc) if err != nil { panic(err) } fmt.Println(previousDoc) } |
6、事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | // 取消关注 func UnFollowRelation(ctx context.Context, followee int64, follower int64) error { userColl := MongoCli.Database( "tiktok" ).Collection( "user" ) // 定义事务 callback := func (sessCtx mongo.SessionContext) ( interface {}, error) { // 是否关注 err := userColl.FindOne(sessCtx, bson.D{{ "user_id" , followee}, { "followers" , bson.D{{ "$all" , bson.A{follower}}}}}).Err() if err != nil { if err == mongo.ErrNoDocuments { return nil, errors.New( "the user is not followed" ) } log.Printf( "%v\n" , err) return nil, err } filter := bson.D{{ "user_id" , followee}} update := bson.D{ { "$inc" , bson.D{{ "follower_count" , -1}}}, { "$pull" , bson.D{{ "followers" , follower}}}, } if updateResult, err := userColl.UpdateOne(sessCtx, filter, update); err != nil { return nil, err } else if updateResult.MatchedCount == 0 { return nil, errors.New( "no followee was found" ) } filter = bson.D{{ "user_id" , follower}} update = bson.D{ { "$inc" , bson.D{{ "follow_count" , -1}}}, { "$pull" , bson.D{{ "follows" , followee}}}, } if updateResult, err := userColl.UpdateOne(sessCtx, filter, update); err != nil { return nil, err } else if updateResult.MatchedCount == 0 { return nil, errors.New( "no follower was found" ) } return nil, nil } // 开启会话 session, err := MongoCli.StartSession() if err != nil { log.Printf( "ERROR: fail to start mongo session. %v\n" , err) return err } defer session.EndSession(ctx) // 执行事务 _, err = session.WithTransaction(ctx, callback) if err != nil { log.Printf( "ERROR: fail to UnFollowRelation. %v\n" , err) return err } return nil } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
2021-06-05 go语言学习笔记五(数组和切片)