首页 > 数据库 >go语言mongodb操作

go语言mongodb操作

时间:2023-08-03 09:58:41浏览次数:46  
标签:语言 err nil mongodb age context go bson TODO

MongoDB属于非关系型数据库,它是由C++编写的分布式文档数据库。内部使用类似于Json的bson二 进制格式。

官方文档:https://www.mongodb.com/docs/drivers/go/current/fundamentals/

相关文档:https://www.w3cschool.cn/mongodb/mongodb-1uxs37ih.html

连接

package main

import (
    "context"
    "fmt"
    "log"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

const mongo_uri = "mongodb://172.24.233.212:27017/?maxPollSize=20&w=majority&connectTimeoutMS=1000"

var (
    mongc *mongo.Client
    err   error
)
func init() {
    opts := options.Client().ApplyURI(mongo_uri) // 返回一个客户端配置选项类型
    mongc, err = mongo.Connect(context.TODO(), opts)
    if err != nil {
        log.Fatal(err)
    }
    err = mongc.Ping(context.TODO(), nil)
    if err != nil {
        log.Fatal(err)
    }
}
func main() {
    defer func() {
        if err = mongc.Disconnect(context.TODO()); err != nil {
            log.Fatal(err)
        }
    }()

        fmt.Println(mongc)  
}
连接

基本概念

MongoDB中可以创建使用多个库,但有一些数据库名是保留的,可以直接访问这些有特殊作用的数据 库。

admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数 据库或者关闭服务器。

local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合

config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。

数据封装

结构体定义: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)
}

tag参考:https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/#struct-tags

User结构体中ID一定要使用omitempty,新增时结构体,如果ID不设置则为零值提交,数据库中_id字段 就是一串0。如果设置忽略零值,ID为0提交时会被忽略,数据库则自动生成_id中的id。

ObjectId有12字节组成,参考 bson/primitive/objectid.go/NewObjectID()函数:4字节时间戳 + 5字节进程唯一值 + 3字节随机数,每次加1

package main

import (
    "context"
    "fmt"
    "log"

    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

const mongo_uri = "mongodb://172.24.233.212:27017/?maxPollSize=20&w=majority&connectTimeoutMS=1000"

var (
    mongc *mongo.Client
    err   error
)

type Student struct {
    Id int `bson:"_id,omitempty"`
    Name    string
    Age     uint8
    Address string
}

func init() {
    opts := options.Client().ApplyURI(mongo_uri) // 返回一个客户端配置选项类型
    mongc, err = mongo.Connect(context.TODO(), opts)
    if err != nil {
        log.Fatal(err)
    }
    err = mongc.Ping(context.TODO(), nil)
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    defer func() {
        if err = mongc.Disconnect(context.TODO()); err != nil {
            log.Fatal(err)
        }
    }()

    u0 := mongc.Database("gopher").Collection("students")
    // 单条插入
    // s0 := Student{Name:"jerry", Age: 13, Address: "美国纽约"}
    // result, err := u0.InsertOne(context.TODO(), s0)

    // 多条插入
    s1 := []interface{}{
        Student{Name: "lily", Age: 23, Address: "西班牙"},
        Student{Name: "hellen", Age: 22},
        Student{Name: "lucy", Address: "德国慕尼黑"},
    }

    result, err := u0.InsertMany(context.TODO(), s1)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(result)

}
单条和多条插入

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

查询

bson.D{{"name", "tom"}}

  • bson.D是切片,D后的{}表示切片字面量定义
  • {"name", "tom"}表示一个结构体实例字面量定义, "name"是结构体的Key属性,类型是string, "tom"是结构体的Value属性,类型是any

bson.M{"name": "tom"}

  • bson.M是map,M后的{}表示该map的字面量定义
  • map类型为map[string]interface{}

 单条查询

package main

import (
    "context"
    "fmt"
    "log"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

const mongo_uri = "mongodb://172.24.233.212:27017/?maxPollSize=20&w=majority&connectTimeoutMS=1000"

var (
    mongc *mongo.Client
    err   error
)

type Student struct {
    Id      primitive.ObjectID `bson:"_id,omitempty"`
    Name    string
    Age     uint8
    Address string
}

func init() {
    opts := options.Client().ApplyURI(mongo_uri) // 返回一个客户端配置选项类型
    mongc, err = mongo.Connect(context.TODO(), opts)
    if err != nil {
        log.Fatal(err)
    }
    err = mongc.Ping(context.TODO(), nil)
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    defer func() {
        if err = mongc.Disconnect(context.TODO()); err != nil {
            log.Fatal(err)
        }
    }()
    u0 := mongc.Database("gopher").Collection("students")
    // 查询条件,利用bson来构建,bson.D是类型
    var r Student
    err = u0.FindOne(context.TODO(), bson.D{}).Decode(&r)
    if err != nil {
        // 查无此文档错误类型判断
        if err == mongo.ErrNoDocuments {
            return
        }
        fmt.Println(err)
    }
    fmt.Println("@@@", r)
}
单条查询

 返回结果:

 多条查询

type Student struct {
    Id      primitive.ObjectID `bson:"_id,omitempty"`
    Name    string
    Age     uint8
    Address string
}

func findMany() {
    // bson.D可以理解为切片,bson.M可以理解为map
    // filtd := bson.D{{Key: "name", Value: "tom"}, {Key: "age", Value: 29}}
    // filtm := bson.M{"name": "tom", "age": 29}
    // 根据id来查询时,需要先将字符串类型的id转换成objectid类型
    id, err := primitive.ObjectIDFromHex("64c75a6770ed7b94a7960212")
    if err != nil {
        log.Fatal(err)
    }
    filtd := bson.D{{"_id", id}}
    cursor, err := stds.Find(context.TODO(), filtd)
    if err != nil {
        log.Fatal(err)
    }
    var s0 Student
    defer cursor.Close(context.TODO())
    for cursor.Next(context.TODO()) {
        err = cursor.Decode(&s0)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(s0)
    }
}
示例1
type Student struct {
    Id      primitive.ObjectID `bson:"_id,omitempty"`
    Name    string
    Age     uint8
    Address string
}
func findMany2() {
    filtd := bson.D{{"name", "tom"}}
    cursor, err := stds.Find(context.TODO(), filtd)
    if err != nil {
        log.Fatal(err)
    }
    var s0 []Student
    err = cursor.All(context.TODO(), &s0)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(s0)
}
示例2
func findByFilter(filter any) {
    cursor, err := stds.Find(context.TODO(), filter)
    if err != nil {
        log.Fatal(err)
    }
    // 关闭游标
    defer cursor.Close(context.TODO())
    var s0 []Student
    err = cursor.All(context.TODO(), &s0)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(s0)
}
func main() {
    //多条查询,条件前用$,gt/lt/eq/ne/gte/lte,多个条件为and关系
    // filtd := bson.D{{"age", bson.M{"$gt": 20}}}
    // filtm := bson.M{"age": bson.D{{"$ne", 23}}}
    // in和notin逻辑
    // filtm := bson.M{"name": bson.M{"$in": []string{"tom", "lily"}}}
    // filtd := bson.D{{"name", bson.D{{"$nin", []string{"lucy", "hellen"}}}}}
    // and、or逻辑,注意array类型
    // filtd := bson.D{{"$or", []bson.M{{"name": "tom"}, {"age": bson.M{"$gt": 20}}}}}
    // 查询时,字段的类型与值要对应,如果下面的age的值29为string,将查找为空
    // filtm := bson.M{"$and": []bson.M{{"name": "tom"}, {"age": 29}}}
    // not逻辑,写法有点绕
    filtm := bson.M{"name": bson.M{"$not": bson.M{"$eq": "tom"}}}
    findByFilter(filtm)
}
多条件查询
比较符号 含义 filter示例
$lt 小于 bson.M{"age": bson.M{"$lt": 20}}
$gt 大于 bson.M{"age": bson.M{"$gt": 20}}
$lte 小于等于

bson.M{"age": bson.M{"$lte": 20}}

bson.D{{"age", bson.D{{"$lte", 20}}}}

$gte 大于等于 bson.M{"age": bson.M{"$gte": 20}}
$ne 不等于 bson.M{"age": bson.M{"$ne": 20}}
$eq 等于,默认为等于

bson.M{"age": bson.M{"$eq": 20}}

bson.M{"age": 20}

$in 在范围内 bson.M{"age": bson.M{"$in": []int{16, 33}}}
$nin 不在范围内 bson.M{"age": bson.M{"$nin": []int{16, 33}}}

https://www.mongodb.com/docs/manual/reference/operator/query/and/

逻辑符号 含义 示例
$and

bson.M{"$and": []bson.M{{"name": "tom"}, {"age": 33}}}

bson.M{"$and": []bson.M{{"name": "tom"}, {"age": bson.M{"$gt": 40}}}}

$or bson.M{"$or": []bson.M{{"name": "tom"}, {"age": bson.M{"$lt": 20}}}}
$not

bson.M{"age": bson.M{"$not": bson.M{"$gte": 20}}}

bson.M{"age": bson.M{"$gte": 20}} 取反为 bson.M{"age": bson.M{"$not": bson.M{"$gte": 20}}}

元素  含义 示例
$exists 文档中是否有这个字段 bson.M{"Name": bson.M{"$exists": true}}
$type 字段是否是指定的类型 bson.M{"age": bson.M{"$type": 16}}

bson.M{"name": bson.M{"$exists": true}} 标识所有具有Name字段的文档,注意Name和name 不一样。

常用类型,参考 https://docs.mongodb.com/manual/reference/operator/query/type/#op._S_type

 

  • 字符串类型编码为2,别名为string
  • 整型编码为16,别名为int
  • 长整型编码为18,别名为long

投影

func findByOpts(filter any, opts *options.FindOptions) {
    cursor, err := stds.Find(context.TODO(), filter, opts)
    if err != nil {
        log.Fatal(err)
    }
    var s0 Student
    defer cursor.Close(context.TODO())
    for cursor.Next(context.TODO()) {
        err = cursor.Decode(&s0)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(s0)
    }
}

func main() {
    // limit+投影,true、1为-1、false相反
    opts := options.Find().SetLimit(3).SetProjection(bson.M{"name": true, "age": 1})
    // 排序,1为升序,-1为降序,其他报错
    opts.SetSort(bson.M{"age": -1})
    filtm := bson.M{"age": bson.M{"$gt": 23}}
    findByOpts(filtm, opts)
}
投影+排序

分页

opt.SetSkip(1)  // offset
opt.SetLimit(1) // limit

更新

更新操作符 含义 示例
$inc 对给定字段数字值增减 bson.M{"$inc": bson.M{"age": -5}}
$set 设置字段值,如果字段不存在则创 建 bson.M{"$set": bson.M{"gender": "M"}}
$unset 移除字段 {'$unset':{'Name':""}}

 

// 更新一条
func updateOne(filter any, update any) {
    // 更新一条,即使条件能匹配多条,也会匹配一条更新
    r, err := stds.UpdateOne(context.TODO(), filter, update)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("匹配到%v条; 更新了%v条\n", r.MatchedCount, r.ModifiedCount)
}

// 更新多条
func updateMany(filter any, update any) {
    r, err := stds.UpdateMany(context.TODO(), filter, update)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("匹配到%v条; 更新了%v条\n", r.MatchedCount, r.ModifiedCount)
}

func main() {
    // filter := bson.M{"age": bson.M{"$gt": 20}}
    // update := bson.M{"$set": bson.M{"address": "北京"}}
    // filter := bson.M{"name": "lucy", "age": 0}
    // update := bson.M{"$unset": bson.M{"address": ""}}
    // updateOne(filter, update)
    filter := bson.M{"name": "lucy"}
    // $inc自增减配置
    update := bson.M{"$set": bson.M{"address": "上海"}, "$inc": bson.M{"age": -3}}
    updateMany(filter, update)
}
更新

替换

type Stud struct {
    Name string
    Age  int
}

func replace(filter any, replacement any) {
    // 更新并返回更新前的文档
    // r := stds.FindOneAndReplace(context.TODO(), filter, replacement)
    // o := Student{}
    // r.Decode(&o)
    // fmt.Println(o)
    r, err := stds.ReplaceOne(context.TODO(), filter, replacement)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("匹配到%v条; 替换了%v条\n", r.MatchedCount, r.ModifiedCount)
}

func main() {
    // 替换,其实是用实例来更新
    s0 := &Stud{Name: "kaluo", Age: 99}
    filter := bson.M{"name": "lily"}
    replace(filter, s0)

}
替换

 删除

// 删除一个
func deleteOne() {
 filter := bson.M{} // 没有条件,匹配所有文档
 dr, err := users.DeleteOne(context.TODO(), filter)
 if err != nil {
 log.Fatal(err)
 }
 fmt.Println(dr.DeletedCount)
}
// 删除多个
func deleteMany() {
 filter := bson.M{} // 没有条件,匹配所有文档
 dr, err := users.DeleteMany(context.TODO(), filter)
 if err != nil {
 log.Fatal(err)
 }
 fmt.Println(dr.DeletedCount)
}

users.DeleteMany(context.TODO(), bson.M{}) 是删除所有文档,危险!

标签:语言,err,nil,mongodb,age,context,go,bson,TODO
From: https://www.cnblogs.com/caibao666/p/17593781.html

相关文章

  • 初学C语言day09--宏定义
    预处理指令程序员所编写的代码并不是能被编译器直接编译的标准C代码,需要一段程序翻译一下翻译的程序称为预处理器,翻译的过程叫做预处理,需要被翻译的代码叫做预处理指令,以#开头的都是预处理指令查看预处理结果:gcc-Ecode.c把预处理的结果显示到终端gcc-Ecode.c-ocode......
  • python django中的权限控制
    权限控制基于form组件实现1.配置文件编写权限关系表有权限控制,意味着要登录,需要提前把登录页面放到白名单,在setting.py文件写入白名单内的路径不做访问控制和登录认证WHITE_URL=["/web/login/","/web/sms_login","web/sms_send","/web/logout/"]在setting.py文件写......
  • golang用pgx查询数据时如何将查询结果方便的放入Map中
    pgx库简介下面是来自官网的简介:pgx-PostgreSQL驱动和工具包pgx是一个用于PostgreSQL的纯Go语言驱动和工具包。pgx驱动是一个底层的高性能接口,暴露了PostgreSQL特有的功能,如LISTEN/NOTIFY和COPY。它还包含一个标准database/sql接口的适配器。工具包组件是一组相关的包,实......
  • 【视频】R语言用线性回归预测共享单车的需求和可视化|数据分享
    全文链接:https://tecdat.cn/?p=33350原文出处:拓端数据部落公众号分析师:ShuliWang自行车共享系统是新一代的传统自行车租赁,从会员,租赁到归还的整个过程已经自动化。通过这些系统,用户可以轻松地从特定位置租用自行车,然后在另一个位置返回。目前,全球约有500多个自行车共享计划,其......
  • 数据分享|R语言ARIMA模型分析预测上海空气质量指数AQI时间序列|附代码数据
    全文链接:http://tecdat.cn/?p=32265原文出处:拓端数据部落公众号最近我们被客户要求撰写关于上海空气质量指数的研究报告,包括一些图形和统计输出。指数平滑法对于预测来说是非常有帮助的,而且它对时间序列上面连续的值之间相关性没有要求。但是,如果你想使用指数平滑法计算出预测......
  • 自然语言处理 Paddle NLP - 词法分析技术及其应用
    词法分析就是利用计算机对自然语言的形态(morphology)进行分析,判断词的结构和类别等。”简单而言,就是分词并对每个词进行分类,包括:分词、词性标注、实体识别三个任务问答知识图谱,类似一张表,里面放了姚明(人)、妻子(属性)对应的是谁这张表来源于网页挖掘,也是词法分析,进行对应识别对话......
  • 自然语言处理 Paddle NLP - 文本语义相似度计算(ERNIE-Gram)
    基于预训练模型ERNIE-Gram实现语义匹配1.背景介绍文本语义匹配任务,简单来说就是给定两段文本,让模型来判断两段文本是不是语义相似。在本案例中以权威的语义匹配数据集LCQMC为例,LCQMC数据集是基于百度知道相似问题推荐构造的通问句语义匹配数据集。训练集中的每两段文本都会被......
  • Golang反射type和kind有什么区
    一、前言Go语言中的反射是由reflect包提供支持的,它定义了两个重要的类型Type和Value。任意值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。在Go语......
  • Gin框架dgrijalva/jwt-go实例(JWT用户认证)
    1.什么是JWTJWT(JSONWebToken)是一个非常轻巧的规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,一个JWT由三部分组成,Header头部,Claims载荷,Signature签名JWT原理类似我们加盖公章或手写签名的的过程,合同上写了很多条款,不是随便一张纸随便写啥都可以的,......
  • 模型:Django与Mysql交互
     1、创建数据库用户前提是已经在本机或者服务器上安装了mysql。createdatabaseslw;createuser'slw'@'%'identifiedby'pwd'grantallprivilegesonslw.*to'slw'@'%'identifiedby'pwd'withgrantoption;flushprivile......