mongodb学习笔记(2)go语言操作mongodb

1、安装驱动包

1.1安装mongoDB Go驱动包

go get github.com/mongodb/mongo-go-driverl

1.2通过go连接MongoDB

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连接池模式

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数据:DRaw

类型D家族被用来简洁地构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用。D家族包括四类:

    • D:一个BSON文档。这种类型应该在顺序重要的情况下使用,比如MongoDB命令。
    • M:一张无序的map。它和D是一样的,只是它不保持顺序。
    • A:一个BSON数组。
    • E:D里面的一个元素。

2.2导入包

要使用BSON,需要先导入下面的包:

import "go.mongodb.org/mongo-driver/bson"

 

3、CRUD

3.1概述

下面以user和video这两个结构体来演示mongodb的CRUD,它们的结构如下所示:

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插入元素

//插入单个数据
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)
}

 

//查询到匹配数据则修改,否则就插入
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删除元素

//删除一条文档
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更新文档

//更新多条文档
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)
}

 

//替换文档
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)
}

  

//向数组添加元素
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查询文档

//查询的单个文档
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、批量操作

//批量操作
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、复合操作

//复合操作:查找和删除
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、事务

// 取消关注
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
}

  

 

 

 

 

 

 

 

参考:Go语言操作mongoDB | 李文周的博客 (liwenzhou.com)

 参考:Context — Go (mongodb.com)

posted @ 2022-06-05 11:22  ☞@_@  阅读(303)  评论(0编辑  收藏  举报