MongoDB介绍
MongoDB是一种非关系型数据库,C++编写的分布式文档型号数据库,内部使用类似于JSON的bson二进制格式。支持单机、主从(废弃)、副本集、Sharding分片等多种高可用架构。具体参考 https://blog.51cto.com/oldlees/7273362
驱动
驱动:https://www.mongodb.com/docs/drivers/
Go驱动: https://www.mongodb.com/docs/drivers/go/current/
驱动安装
连接字符串
mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
参考: https://www.mongodb.com/docs/manual/reference/connection-string/#examples
示例: https://www.mongodb.com/docs/drivers/go/current/fundamentals/connection/#connection-example
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const uri = "mongodb://192.168.131.12:27017"
var client *mongo.Client
var err error
func init() {
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI).SetConnectTimeout(time.Second * 5)
client, err = mongo.Connect(context.TODO(), opts)
if err != nil {
panic(err)
}
}
func main() {
defer func() {
if err = client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
var result bson.M
if err := client.Database("admin").RunCommand(context.TODO(), bson.D{{"ping", 1}}).Decode(&result); err != nil {
panic(err)
}
fmt.Println("Pinged your deployment. You successfully connected to MongoDB!")
}
数据封装
结构体定义:https://www.mongodb.com/docs/drivers/go/current/usage-examples/findOne/#find-a-document
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Name string
Age int
}
func (u *User) String() string {
return fmt.Sprintf("%s: %s,%d", u.ID, u.Name, u.Age)
}
func main() {
var u = User{
Name: "blee", Age: 99,
}
fmt.Println(u.String()) //ObjectID("000000000000000000000000"): blee,99
}
tag参考:https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/#struct-tags
User结构中的ID一定要使用omitempty
,新增时结构体如果ID不设置则为零值提交,数据库中 _id
字段就是0字符串。
如果设置忽略零值,ID为0提交时会被忽略,数据自动生成 _id
ObjectId
由12个字节组,参考:bson/primitive/objectid.go
源码文件。
- 4字节时间戳
- 5字节进程唯一值
- 3字节随机数,每次增加1
插入数据
参考:https://www.mongodb.com/docs/drivers/go/current/usage-examples/
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson/primitive"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const uri = "mongodb://192.168.131.12:27017"
var client *mongo.Client
var db *mongo.Database
var users *mongo.Collection
func init() {
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI).SetConnectTimeout(time.Second * 5)
var err error
client, err = mongo.Connect(context.TODO(), opts)
if err != nil {
panic(err)
}
db = client.Database("test")
users = db.Collection("users") //初始化集合
}
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Name string
Age int
}
func (u User) String() string {
return fmt.Sprintf("%s: %s,%d", u.ID, u.Name, u.Age)
}
func insertOne() { //插入一条数据
tom := User{Name: "tom", Age: 33}
insertOneResult, err := users.InsertOne(context.TODO(), tom) //context.TODO()空白上下文
if err != nil {
log.Println(err)
}
fmt.Println(insertOneResult.InsertedID)
}
func main() {
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
insertOne()
}
//插入多条
func insertMany() {
jerry := User{Name: "jerry", Age: 20}
ben := User{Name: "ben", Age: 16}
insertManyResult, err := users.InsertMany(context.TODO(), []interface{}{jerry, ben})
if err != nil {
log.Println(err)
}
fmt.Println(insertManyResult.InsertedIDs...)
}
BSON
参考:https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/
MongoDB的Go库提供了构建BSON的数据类型分为4种:
D
: An ordered representation of a BSON document (slice) 表示有序的,切片切元素是二元的M
: An unordered representation of a BSON document (map) 表示无序的,map且元素是kv对
A
: An ordered representation of a BSON array 有序的数组E
: A single element inside a D type 单个元素
具体使用参考以下:
查询
原始数据如下:
单条查询
1、解释bson.D{{"name","tom"}}
:
type D []E
// E represents a BSON element for a D. It is usually used inside a D.
type E struct {
Key string
Value interface{}
}
bson.D
是切片,D后面的{}
表示切片的字面量定义{"name","tom"}
表示一个结构体实例字面量
- name 是结构体E的key属性,string
- tome 是结构体的Value属性,空接口
2、解释bson.M{{"name","tom"}}
:
// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
type M = primitive.M
// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
type M map[string]interface{}
bson.M
是map,M后面的{}
表示该map的字面量定义- map类型为
type M map[string]interface{}
func findOne() {
filter := bson.D{{"name", "tom"}} //切片
//filter := bson.D{{"name", bson.D{{"$eq", "tom"}}}} //指定等值条件
//filter := bson.M{"name": "ben"} //map
//filter := bson.M{"name": bson.M{"$ne": "ben"}}
//filter := bson.D{} //没有条件表示全部符合
var u User
err := users.FindOne(context.TODO(), filter).Decode(&u)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) { //var ErrNoDocuments = errors.New("mongo: no documents in result")
//说明没有符合条件的文档
log.Println("没有符合条件的数据")
return
}
log.Println(err)
}
fmt.Println(u) //ObjectID("64ed983d3defd3e8f0351c1a"): tom,33 默认返回匹配到的第一条
}
多条查询
//查询多条,遍历结果
func findMany() {
filter := bson.M{} //无条件,全部符合
cursor, err := users.Find(context.TODO(), filter)
if err != nil {
log.Println(err)
}
defer cursor.Close(context.TODO()) //关闭游标
var results []*User
for cursor.Next(context.TODO()) {
var u User
err = cursor.Decode(&u)
if err != nil {
log.Println(err)
}
results = append(results, &u) //将数据装入切片中
}
fmt.Println(results)
}
//查询多条,批量处理
func findManyB() {
filter := bson.D{} //无条件,全部符合
var results []*User
cursor, err := users.Find(context.TODO(), filter)
if err != nil {
log.Println(err)
}
defer cursor.Close(context.TODO())
err = cursor.All(context.TODO(), &results)
if err != nil {
log.Println(err)
}
for i, result := range results {
fmt.Println(i, result)
}
}
条件查询
func findByFilter(filter interface{}) {
var results []*User
cursor, err := users.Find(context.TODO(), filter)
if err != nil {
log.Println(err)
}
defer cursor.Close(context.TODO())
err = cursor.All(context.TODO(), &results)
if err != nil {
log.Println(err)
}
fmt.Println(results)
}
func main() {
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
filter := bson.M{"age": bson.M{"$lt": 20}} //定义条件,传入函数,filter参考下表:
findByFilter(filter)
}
filter操作符
比较符 | 示例 |
$lt 小于 |
|
$gt 大于 |
|
$lte 小于等于 |
|
$gte 大于等于 |
|
$ne 不等于 |
|
$eq 等于,也可以不用,默认就是等值 |
|
$in 在范围内 |
|
$nin 不再范围内 |
|
逻辑符号 | 示例 |
$and 与 |
|
$or 或 |
|
$not 非 |
|
元素 | 示例 |
$exists 是否存在这个字段 |
返回所有有Name字段的文档,注意大小写 |
$type 字段是否是指定类型 |
16表示类型代号 |
常用类型参考:https://www.mongodb.com/docs/manual/reference/operator/query/type/#op._S_type
- 字符串类型编码为2,别名为string
- 整型编码为16,别名为int
- 长整型编码为18,别名为long
带options选项的查询
func findAll(filter interface{}, opt *options.FindOptions) { //示例化FindOptions对象
var results []*User
cursor, err := users.Find(context.TODO(), filter, opt)
if err != nil {
log.Println(err)
}
defer cursor.Close(context.TODO()) //关闭游标
err = cursor.All(context.TODO(), &results)
if err != nil {
log.Println(err)
}
fmt.Println(results)
}
func main() {
defer func() {
if err := client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
filter := bson.M{"age": bson.M{"$type": 16}}
findAll(filter, options.Find().SetLimit(2))
}
字段投影
filter := bson.M{"age": bson.M{"$gt": 18}}
//opt := options.Find().SetProjection(bson.M{"name": false, "age": false}) //name age字段不显示
opt := options.Find().SetProjection(bson.M{"name": true}) //name投影,age显示零值
findAll(filter, opt)
//findAll参考上例
排序
filter := bson.M{"age": bson.M{"$gt": 18}}
opt := options.Find().SetSort(bson.M{"age": 1}) //升序
//opt := options.Find().SetSort(bson.M{"age": -1}) //降序
findAll(filter, opt)
分页
filter := bson.M{"age": bson.M{"$gt": 18}}
opt := options.Find().SetSkip(1).SetLimit(2)
//offset(1) limit(2)
更新
更新符号 | 示例 |
$inc 对指定的字段数值增减 |
|
$set 设置字段值,如果字段不存在则创建,存在则更新 |
|
$unset 移除字段 |
|
//更新一条
func updateOne() {
filter := bson.M{"age": bson.M{"$exists": true}} //所有有age字段的文档
updateOps := bson.M{"$inc": bson.M{"age": -5}} //age字段减5
updateResult, err := users.UpdateOne(context.TODO(), filter, updateOps)
if err != nil {
log.Println(err)
}
fmt.Println(updateResult.MatchedCount, updateResult.ModifiedCount) //默认修改第一条匹配
}
//更新多条
func updateMany() {
filter := bson.M{"age": bson.M{"$exists": true}} //所有有age字段的文档
updateOps := bson.M{"$set": bson.M{"gender": "女"}} //为符合条件的文档设置gender字段
updateResult, err := users.UpdateMany(context.TODO(), filter, updateOps)
if err != nil {
log.Println(err)
}
fmt.Println(updateResult.MatchedCount, updateResult.ModifiedCount)
}
//找到一批更新第一个,ReplaceOne更新除ID以外的所有字段
func updateReplaceOne() {
filter := bson.M{"age": bson.M{"$exists": true}}
replacement := User{
Name: "Sammmm",
Age: 99,
}
updateResult, err := users.ReplaceOne(context.TODO(), filter, replacement)
if err != nil {
log.Println(err)
}
fmt.Println(updateResult.MatchedCount, updateResult.ModifiedCount)
}
删除
func deleteMany() {
filter := bson.M{"age": bson.M{"$gt": 20}} //删除年龄大于20岁的
deleteResult, err := users.DeleteMany(context.TODO(), filter, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(deleteResult.DeletedCount)
}
标签:filter,err,MongoDB,age,Golang,context,Println,操作,bson
From: https://blog.51cto.com/oldlees/7279045