首页 > 数据库 >Golang操作MongoDB

Golang操作MongoDB

时间:2023-08-29 18:34:44浏览次数:45  
标签:filter err MongoDB age Golang context Println 操作 bson

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

Golang操作MongoDB_Go

插入数据

参考: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 单个元素

具体使用参考以下:

查询

原始数据如下:

Golang操作MongoDB_Go_02

单条查询

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  小于

filter := bson.M{"age": bson.M{"$lt": 20}}

$gt 大于

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

$lte 小于等于

bson.M{"age": bson.M{"$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}}}

逻辑符号

示例

$and 与

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

$or 或

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

$not 非

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

元素

示例

$exists

是否存在这个字段

bson.M{"Name": bson.M{"$exists": true}}

返回所有有Name字段的文档,注意大小写

$type

字段是否是指定类型

bson.M{"age": bson.M{"$type": 16}}

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

对指定的字段数值增减

updateOps := bson.M{"$inc": bson.M{"age": -5}}

$set

设置字段值,如果字段不存在则创建,存在则更新

bson.M{"$set": bson.M{"gender": "女"}}

$unset

移除字段

updateOps := bson.M{"$unset": bson.M{"gender": ""}}

//更新一条
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

相关文章

  • 操作系统执行程序原理
    数根据毕达哥拉斯学派的宗旨——万物皆数,那么一切数据(信息)都可以用数来表示,而数又可以转换为二进制数(莱布尼茨在改造帕斯卡的加法器时,提出的二进制概念)。布尔代数GeorgeBoole的布尔代数,则可以将算术运算转换为逻辑运算,人们根据逻辑运算的规律来组建电路,于是电路就可以实现布尔......
  • 初识操作系统
    OS一般指操作系统。操作系统(英语:OperatingSystem,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。OS的功能:1、管理应用程序(安装、运行、关闭、卸载)2、为应用程序提供服务(IO、声频/视频输出、网络等)3、资......
  • 操作系统的启动
    Disk:存放OS&bootloaderBIOS:基本I/O处理系统(OS启动之后,OS开始检测各种外设——自检?)Bootloader:将OS从Disk读取至Memory中,然后将cpu的控制权交给OSPOST(加电自检):寻找显卡和执行BIOS>系统调用>应用程序主动向操作系统发出服务请求>异常(来源于不良的应用程序)>非法指令或其他......
  • golang 协程、延迟函数调用、以及恐慌和恢复
    此篇文章将介绍协程和延迟函数调用。协程和延迟函数调用是Go中比较独特的两个特性。恐慌和恢复也将在此篇文章中得到简单介绍。本文并非全面地对这些特性进行介绍,后面的其它文章会陆续补全本文的未介绍的内容。协程(goroutine)现代CPU一般含有多个核,并且一个核可能支持多线程。......
  • linux防火墙操作
    查看防火墙状态systemctlstatusfirewalld.service开启防火墙systemctlstartfirewalld.service防火墙开机启动systemctlenablefirewalld.service关闭防火墙开机启动systemctldisablefirewalld.service关闭防火墙systemctlstopfirewalld.service查看防火墙状......
  • Git常用操作
    Git基本理解git的工作就是创建和保存项目的快照以及之后的快照进行对比。常用命令: gitclone-拷贝一份远程仓库,就是下载一个项目gitpush-上传远程代码并合并gitadd-添加文件到仓库(实际到暂存区)gitcommit-提交暂存区到本地仓库gitcheckoutgitpull-下载远......
  • Docker:第二章:部署项目,对镜像,容器的操作
    服务器上的项目访问不了,所以我去看了看容器,果然那我就删除容器呗:docker rm容器iddockerrmf097e24a9a0f说明:从镜像到容器,同一个镜像构建多个运行的Docker实体——容器,镜像提供了容器运行时所需的程序、库、资源、配置等文件,还包含了一些为运行时准备的一些配置参数。镜......
  • visual studio 生成dll文件以及修改输出dll文件名称操作
    visualstudio生成dll文件以及修改dll文件名称Windows系统下VisualStudio可以通过.def文件创建dll。一、准备测试代码1.确定需要导出的函数,test.cpp文件中定义如下voidfun1(){ return;}voidfun2(){ return;}intmain(){ return0;}2.添加.def文件,一般添加到源文件下面。......
  • 【3.0】Docker镜像操作
    【一】查找镜像要查找一个特定的Docker镜像,可以使用以下命令:dockersearch镜像名称建议直接在hub.docker.com或其他Docker镜像仓库网站上进行搜索,以获取更直观的结果。在网站上,您可以查看镜像的标签、描述和其他相关信息。举个例子,如果要搜索名为nginx的镜像,可以执......
  • 【4.0】Docker容器操作
    【一】Docker容器操作Docker容器是基于Docker镜像创建的运行实例。把镜像运行成容器,并且一个镜像,可以运行出多个容器【二】运行容器使用以下命令可以将一个Docker镜像运行为一个或多个容器:dockerrun镜像名称每次运行此命令,将创建一个新的容器实例。可以根据需......