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数据:D和Raw。
类型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
}

浙公网安备 33010602011771号