希曼日记

mongodb

本页目录 10
  1. Install
  2. Test
  3. Init
  4. Use
  5. 查询
  6. 插入
  7. 特征
  8. 数据结构
  9. 更新
  10. 删除

Install

go get -u go.mongodb.org/mongo-driver/bson

Test

package test

import (
	"context"
	"fmt"
	"github.com/spf13/viper"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"log"
	"path"
	"runtime"
	"testing"
)

func TestMongoDB(t *testing.T) {
	client, err := mongo.Connect(context.TODO(), options.Client().SetAuth(options.Credential{
		Username: "username",
		Password: "password",
	}).ApplyURI("uri"))
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err = client.Disconnect(context.TODO()); err != nil {
			t.Fatal(err)
		}
	}()

	// Ping the primary
	if err := client.Ping(context.TODO(), readpref.Primary()); err != nil {
		t.Fatal(err)
	}
	fmt.Println("Successfully connected mongodb and pinged.")
}

func GetPath(file, dir string) string {
	if dir == "" {
		dir = "/config/"
	}
	_, filename, _, _ := runtime.Caller(0)
	root := path.Dir(path.Dir(filename)) //获取当前工作目录
	dirPath := path.Dir(root + dir)      // 获取配置文件的目录
	filePath := path.Join(dirPath, file) // 获取配置文
	return filePath
}

Init

  1. 定义一个保存数据库的URI常量
  • 自建服务器格式: Pasted image 20230114031810
  • Mongo的集群的服务器格式:
mongodb+csv://user:pass@sample.host:27017/

例:

const URI = "mongodb://root:msdnmm@192.168.0.152:27017/"
  1. 创建客户端 mongodb 语法:
mongo.Connect(context,options.Client().ApplyURI(uri)) (client, err)

参数

  1. context: 上下文
  2. options: 选项, 用于连接数据库的选项
  3. uri: 数据库的URI
const URI = "mongodb://root:msdnmm@192.168.0.152:27017/"
var Client, MongodbErr = mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if MongodbErr != nil {
	panic(MongodbErr)
} 
  1. 连接数据库文档

语法:

mongo.Connect(context.TODO(), options.Client().ApplyURI(URI)).Database("database_name").Collection("collection_name")

参数: Database: 数据库名 Collection: 文档名(表名)

例:

var Client, MongodbErr = mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if MongodbErr != nil {
	panic(MongodbErr)
} 
coll := Client.Database("golang").Collection("users")

Use

单结果查询FindOne()

find 语法:

struct.FindOne(content, filter).Decode(&strcut) err

参数:

FindOne:

  1. content: 上下文
  2. filter: 查询条件

Decode:

  1. strcut 结构体, 需要传递该结构体的指针, 进行修改

返回值:

  1. 失败信息 查询失败返回mongo.ErrNoDocuments

使用:

  1. 定义结构体接收数据库返回的值, 一般与数据库的字段相对应
  2. 定义查询条件
  3. 查询
  4. 将返回的bson二进制json结果转成所需格式

前提:

向数据库插入如下指令:

use golang_server
db.users.insertOne({
  username:"lisa",
  password:"123456"
})

例:

// Person 用户结构
type Person struct {
	Username string `json:"username" bson:"username" binding:"required,min=1,max=20"` // 如果需要对数据传递参数, 必须使用bson 这个tag
	Password string `json:"password" binding:"required,min=1,max=20"`
}

var Client, MongodbErr = mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if MongodbErr != nil {
	panic(MongodbErr)
} 

func main() {
    coll := Client.Database("golang_server").Collection("ratings") // 连接数据库
	var person Person
	filter := bson.D{{"username", "lisa"}} // 设置查询条件
	// 返回结果, 如果成功则将返回的bson结果绑定到结构体
	err := person.FindOne(content.TODO(), filter).Decode(&person)
	if err != nil {
		if findErr == mongo.ErrNoDocuments{
			fmt.Println("要查询的数据在数据库中不存在")
		}
		panic(result.re)
	}
	res,_ := json.Marshal(person) // 将bson二进制json转为json
	fmt.Println(string(res)) // 以字符串形式输出转换结果
}

多结果查询Find()

语法:

result, err := struct.Find(context, filter) (result, err)
err = result.All(context, &result) (err)

参数:

Find:

  1. struct: 结构体
  2. context: 上下文
  3. filter: 查询条件

返回值:

  1. result: 查询结果
  2. err: 错误消息

All:

  1. context: 上下文
  2. result: 返回的结果

返回值:

  1. err: 错误消息

使用:

  1. 定义结构体Tea接收数据库返回的值, 一般与数据库的字段相对应
  2. 定义filter查询条件
  3. 通过Find()查询
  4. 通过All()获取全部返回的结果
  5. 通过for rang遍历输出数据(可选)
  6. 通过json.Marshal()将返回的bson二进制json结果转成所需格式

例:

前提:golang_server数据库的ratings文档(表)插入如下字段

use golang_server
db.ratings.insertMany([
  { type: "Masala", rating: 10, vendor: ["A", "C"] },
  { type: "English Breakfast", rating: 6 },
  { type: "Oolong", rating: 7, vendor: ["C"] },
  { type: "Assam", rating: 5 },
  { type: "Earl Grey", rating: 8, vendor: ["A", "B"] },
])

例:

type Tea struct {
Type string   `json:"type" bson:"Type"`
Rating int32    `json:"rating" bson:"Rating"`
Vendor []string `json:"vendor" bson:"vendor,omitempty" json:"vendor,omitempty"`
}

var Client, MongodbErr = mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if MongodbErr != nil {
	panic(MongodbErr)
} 

func main(){
  coll := client.Database("golang_server").Collection("ratings") // 连接数据库
  filter := bson.D{{"type", "Oolong"}} // 定义查询条件
  var results []Tea // 定义切片结构体(Find返回多个可能结果)
  result, err := coll.Find(context.TODO(), filter)                        // 查询

  // 处理错误, 如果没有错误则将result查询的结果赋值给结构体results
  if err = result.All(context.TODO(), &results); err != nil {
  	panic(err)
  } 
  // 循环获取输出获取到的值
  for _, result1 := range results {
  	res, _ := json.Marshal(result1)
  	fmt.Println("res:", string(res))
  } 
  c.JSON(http.StatusOK, gin.H{
  	"result": results,
  })
}

查询

返回指定字段

关键字: SetProjection

filter := bson.D{{}}
opts := options.Find().SetProjection(bson.D{{"name", 1},{"number",1}})
cursor, err := dbBasic.Find(context.TODO(), filter, opts)

排序

语法: key: 要排列的字段 0/1: 倒序/正序排列

filter := bson.D{{<query>:<value>}}
opt := options.Find().SetSort(bson.D{{<key>:<0/1>}}) // 选项
cursor, err := db.Client.
	Database("Database").
	Collection("Collection").
	Find(context.TODO(),filter, opt)

示例: 查询im数据库的message_basic文档中的created_at, 对created_at进行正序排序

import "go.mongodb.org/mongo-driver/mongo/options"
func MessageList(c *gin.Context) {
	opt := options.Find().SetSort(bson.D{{"created_at", 1}})
	cursor, err := db.Client.
		Database("im").
		Collection("message_basic").
		Find(context.TODO(), bson.D{{}}, opt)
	if err != nil {
		log.Fatalln(err)
		return
	}

	var message []schema.MessageBasic

	if err = cursor.All(context.TODO(), &message); err != nil {
		log.Fatalln(err)
		return
	}
	fmt.Println("message:", message)
	c.JSON(http.StatusOK, gin.H{
		"code":    http.StatusOK,
		"message": "获取成功",
		"body":    message,
	})
}

查询全部

mongodb 返回值: []map(string)any

type MessageBasic struct {
	//ID           primitive.ObjectID `bson:"_id" json:"id"`
	UserIdentity string `json:"user_identity"`
	RoomIdentity string `json:"room_identity"`
	Data         string `json:"data"`
	CreatedAt    int64  `json:"created_at"`
	UpdatedAt    int64  `json:"updated_at"`
}

func MessageList(c *gin.Context) {

	cursor, err := Client.
		Database("im").
		Collection("message_basic").
		Find(context.TODO(), bson.D{{}})
	if err != nil {
		log.Fatalln(err)
		return
	}

	var message []MessageBasic // 返回结果是多对象的数组. 以切片形式存储

	if err = cursor.All(context.TODO(), &message); err != nil {
		log.Fatalln(err)
		return
	}
	fmt.Println("message:", message)
	c.JSON(http.StatusOK, gin.H{
		"data": message,
	})
}

查询数组是否包含某个值

关键语法: $in

result := db.FindOne(context.Background(), bson.D{{"user_identity", bson.D{{"$in", userIdentity4}}}}).Decode(&user)

示例: 数据库插入数据

db.user_room.insertOne({
 "user_identity":["bc83108c977248daad2f3f815d25cfe5","d22e9e82fab041cc8f8d57d51d6b802d"]
})

golnag查询

type UserRoom struct {
	RoomIdentity []string   `bson:"room_identity"`
}
var user UserRoom
userIdentity := "bc83108c977248daad2f3f815d25cfe5"
var userIdentityArr []string
userIdentityArr := append(userIdentity3, userIdentity)
//roomIdentity := "1"
result := db.FindOne(context.Background(), bson.D{{"user_identity", bson.D{{"$in", userIdentityArr}}}}).Decode(&user)
if result != nil {
	if result == mongo.ErrNoDocuments {
		log.Println("查找不到")
	}
	log.Println("err")
}
fmt.Println("user:", user)

插入

inset

coll := client.Database("tea").Collection("ratings")
docs := []interface{}{
	Tea{Type: "Masala", Rating: 10, Vendor: []string{"A", "C"}},
	Tea{Type: "English Breakfast", Rating: 6},
	Tea{Type: "Oolong", Rating: 7, Vendor: []string{"C"}},
	Tea{Type: "Assam", Rating: 5},
	Tea{Type: "Earl Grey", Rating: 8, Vendor: []string{"A", "B"}},
}
result, err := coll.InsertMany(context.TODO(), docs)
if err != nil {
  panic(err)
}

特征

MongoDB存储是BSON(二进制的JSON),所以对数据库操作(改增删)结构体转成JSON时候必须要注意struct的Tag类型必须是bson

数据结构

BSON MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON) 的二进制表示中。与其他将JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易可靠地处理、排序和比较数据。

总结: 对数据库进行操作(改增删)的时候的结构体类型是bson类型, 否则操作失败

连接MongoDB的Go驱动程序中有两大类型表示BSON数据:DRaw

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

更新

更新某个字段的值

update := bson.D{{"$set", bson.D{{"avatar", args[1]}}}}
	db.Mongo.Database("im").
		Collection(schema.UserBasic{}.Collection()).
		InsertOne(context.TODO(), update)

删除

delete