mongodb
Install
go get -u go.mongodb.org/mongo-driver/bsonTest
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
- 定义一个保存数据库的URI常量
mongodb+csv://user:pass@sample.host:27017/例:
const URI = "mongodb://root:msdnmm@192.168.0.152:27017/"- 创建客户端 mongodb 语法:
mongo.Connect(context,options.Client().ApplyURI(uri)) (client, err)参数
context: 上下文- options: 选项, 用于连接数据库的选项
- 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)}- 连接数据库文档
语法:
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:
content: 上下文filter: 查询条件
Decode:
strcut结构体, 需要传递该结构体的指针, 进行修改
返回值:
- 失败信息
查询失败返回
mongo.ErrNoDocuments
使用:
- 定义结构体接收数据库返回的值, 一般与数据库的字段相对应
- 定义查询条件
- 查询
- 将返回的
bson二进制json结果转成所需格式
前提:
向数据库插入如下指令:
use golang_serverdb.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:
struct: 结构体context: 上下文filter: 查询条件
返回值:
result: 查询结果err: 错误消息
All:
- context: 上下文
- result: 返回的结果
返回值:
err: 错误消息
使用:
- 定义结构体
Tea接收数据库返回的值, 一般与数据库的字段相对应 - 定义
filter查询条件 - 通过
Find()查询 - 通过
All()获取全部返回的结果 - 通过
for rang遍历输出数据(可选) - 通过
json.Marshal()将返回的bson二进制json结果转成所需格式
例:
前提:
向golang_server数据库的ratings文档(表)插入如下字段
use golang_serverdb.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 UserRoomuserIdentity := "bc83108c977248daad2f3f815d25cfe5"var userIdentityArr []stringuserIdentityArr := 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)插入
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数据:D和Raw。
- 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)