Golang+MongoDB 从基础到放弃(一)_此人未设置昵称的博客-程序员宅基地

技术标签: Golang  微服务  linux  golang  数据库  mongodb  


环境 Ubuntu16,MongoDB 4.2.2
官网: https://www.mongodb.com
官网下载地址: https://www.mongodb.com/download-center/community
官网安装教程: https://docs.mongodb.com/manual/administration/install-community
官网shell命令文档: https://docs.mongodb.com/manual/mongo
官网crud文档: https://docs.mongodb.com/manual/crud

一、MongoDB介绍

MongoDB 是一个是一个基于分布式文件存储的数据库,介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

mongoDB中将一条数据存储为一个文档(document),数据结构由键值(key-value)对组成。 其中文档类似于我们平常编程中用到的JSON对象。 文档中的字段值可以包含其他文档,数组及文档数组。

mongoDB相关概念

mongoDB中相关概念与我们熟悉的SQL概念对比如下:

MongoDB术语/概念 说明 对比SQL术语/概念
database 数据库 database
collection 集合 table
document 文档 row
field 字段 column
index index 索引
primary key 主键 MongoDB自动将_id字段设置为主键 primary key

二、安装MongoDB

推荐手动安装:手动教程
如果遇到错误请看这篇文章
如果mongo启动报错不知道为什么请看这篇文章
配置文件弄不明白的看这篇文章
配置文档:

dbpath=/usr/local/mongodb/mongodbserver/data
logpath=/usr/local/mongodb/mongodbserver/logs/mongodb.log
logappend=true

fork=true        #后台运行
journal=false
#quiet=true
#storageEngine=mmapv1

bind_ip=0.0.0.0  #允许任何IP进行连接
port=27017

auth=false       #是否授权连接

Ubuntu服务配置文档
命令

vim /etc/init.d/mongodb
#!/bin/bash

start() {
    
/usr/local/mongodb/bin/mongod  --config /usr/local/mongodb/mongodbserver/etc/mongodb.conf
}

stop() {
    
/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodbserver/etc/mongodb.conf --shutdown
}
case "${1:-''}" in
  'start')
 start
 ;;

'stop')
 stop
 ;;

'restart')
 stop
 start
 ;;
  *)
 echo  
$"Usage: $0 {start|stop|restart}"
 exit 1
esac

自动教程

ubuntu下安装命令

sudo apt-get install -y mongodb

安装完成后用下面的命令查看版本

mongo -version

启动和关闭命令

service mongodb start
service mongodb stop

卸载命令

sudo apt-get --purge remove mongodb mongodb-clients mongodb-server

三、shell模式下MongoDB基本命令

进入MongoDB管理界面命令

mongo   //类似于mysql -uroot -p123

数据库基本操作

show dbs         :显示数据库列表 
show collections :显示当前数据库中的集合(类似关系数据库中的表table) 
show users       :显示所有用户 
use yourDB       :切换当前数据库至yourDB 
db.help()        :显示数据库操作命令 
db.yourCollection.help() :显示集合操作命令,yourCollection是集合名 

创建数据库命令

use School #切换到School数据库。MongoDB 无需预创建School数据库,在使用时会自动创建

创建集合命令

db.createCollection('user') #创建一个聚集集合。MongoDB 其实在插入数据的时候,也会自动创建对应的集合,无需预定义集合

文档的增删改查

插入文档

向集合中插入一条文档

> db.user.insert({
    name:"wd",age:22})
WriteResult({
     "nInserted" : 1 })

插入多条文档

//insert 和 insertMany 都可以
//> db.user.insertMany([{
    name:"wyh",age:22},{
    name:"zjd",age:22}])
> db.user.insert([{
    name:"wyh",age:22},{
    name:"zjd",age:22}])
BulkWriteResult({
    
	"writeErrors" : [ ],
	"writeConcernErrors" : [ ],
	"nInserted" : 2,
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"nRemoved" : 0,
	"upserted" : [ ]
})

查寻

查询一条

> db.user.find({
    name:"wd"})
{
     "_id" : ObjectId("5df4a2c3690102e4083ad64c"), "name" : "wd", "age" : 22 }

查询所有

> db.user.find()
{
     "_id" : ObjectId("5df4a2c3690102e4083ad64c"), "name" : "wd", "age" : 22 }
{
     "_id" : ObjectId("5df4a378690102e4083ad64d"), "name" : "wyh", "age" : 22 }
{
     "_id" : ObjectId("5df4a378690102e4083ad64e"), "name" : "zjd", "age" : 22 }

其余查询命令

db.user.find()  #查询所有记录。相当于:select * from student
db.user.find({
    name: 'lisi'})  #查询name='lisi'的记录。相当于: select * from user where name='lisi'
db.user.find({
    },{
    name:1, age:1}) #查询指定列name、age数据。相当于:select sname,sage from user 。name:1表示返回name列,默认_id字段也是返回的,可以添加_id:0(意为不返回_id)写成{name: 1, age: 1,_id:0},就不会返回默认的_id字段了
db.user.find({
    sname: 'zhangsan', sage: 22}) #and 与条件查询。相当于:select * from user where sname = 'zhangsan' and sage = 22
db.user.find({
    $or: [{
    sage: 22}, {
    sage: 25}]}) #or 条件查询。相当于:select * from user where sage = 22 or sage = 25
db.user.find({
    age:{
    $gt:20}})#大于查询,相当于 select * from user where ago>20 

MongoDB符号对照表

> >= < <= !=
$gt $gte $lt $lte $ne

关系符号对照表

or in not in
$or $in $nin

更新文档

函数原型

db.collection.update(
   <query>,
   <update>,
   {
    
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • update : update的对象和一些更新的操作符(如 , , ,inc…)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入- objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。

修改一条内容,若内容不存在,则放弃插入

//将年龄为22的修改为23
db.user.update({
    age:22},{
    age:23})
WriteResult({
     "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

修改一条内容,内容不存在 则新建

db.user.update({
    age:22},{
    name:"zly",age:22,like:"eat"},true)
WriteResult({
    
	"nMatched" : 0,
	"nUpserted" : 1,
	"nModified" : 0,
	"_id" : ObjectId("5df5e05543101a8d2d42486c")
})

删除文档

db.collection.remove(
   <query>,
   {
    
     justOne: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
  • writeConcern :(可选)抛出异常的级别。

删除一条数据

db.user.remove({
    age:23},1)
WriteResult({
     "nRemoved" : 1 })

其他常用命令

限制只查询一条用limit(), 跳过指定条用 Skip()

db.user.find().limit(1)
{
     "_id" : ObjectId("5df5e05543101a8d2d42486c"), "name" : "zly", "age" : 22, "like" : "eat" }

选择排序方式 sort() 1 表示升序 -1 表示降序

 db.user.find().sort({
    age:-1})
{
     "_id" : ObjectId("5df5e2a436ecef9359a3fc36"), "name" : "wd", "age" : 24, "like" : "study" }
{
     "_id" : ObjectId("5df5e05543101a8d2d42486c"), "name" : "zly", "age" : 22, "like" : "eat" }

索引

db.user.createIndex({
    "name":1})  //为name字段创建索引,1为升序,-1为降序
db.user.createIndex({
    "name":-1},{
    unique:true}) //创建一个值不能重复的索引
db.user.createIndex({
    "createDate":1},{
    expireAfterSeconds:10}) //定时删除数据索引 createDate必须为日期类型
db.user.getIndexes()         //查看集合所有索引
db.user.totalIndexSize()     //查看索引大小
db.user.dropIndex("name_1")  //删除索引
db.user.dropIndexes()        //删除所有索引

Golang操作MongoDB

工具下载地址:github.com/mongodb/mongo-go-driver
推荐文档:https://docs.mongodb.com/manual/reference/connection-string/
官方插件说明文档:https://godoc.org/go.mongodb.org/mongo-driver/mongo
参考大神文章(英):https://www.cnblogs.com/endurance9/p/10409232.html
李老师文章(中):
https://www.liwenzhou.com/posts/Go/go_mongodb/

推荐使用官网的包,也可以用第三方插件mgo

首先 创建库 创建用户用于远程连接

> use school
> use admin
> db.createUser({
    user:"wd",pwd:"123",roles:[{
    role:"readWrite",db:"school"}]})
> db.system.users.find() //查看用户
> 权限说明
    1. 数据库用户角色:read、readWrite;
    2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
    3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
    4. 备份恢复角色:backup、restore;
    5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
    6. 超级用户角色:root  

创建复杂权限方法见连接:http://www.voidcn.com/article/p-stetasvk-bhr.html
创建完成后,修改配置文件,默认在/etc/下面,复制上面的配置。重启服务。

MongoDB连接标准语法:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
  • mongodb:// 这是固定的格式,必须要指定。
  • username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库
  • host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
  • portX 可选的指定端口,如果不填,默认为27017
  • /database 如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开 test 数据库。
  • ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开
    不bb,上代码

简单连接栗子

package main

import (
	"context"
	"fmt"
	"log"

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

func main() {
    
	// 设置客户端连接配置
	ctx, mongoclos := context.WithCancel(context.Background())
	defer mongoclos()
	//先在数据库设置用户名密码,再用MongoDB Compass测试一下是否能够连接,再用代码测试
	clientOptions := options.Client().ApplyURI(`mongodb://wd:[email protected]:27017/school`)

	// 连接到MongoDB
	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
    
		log.Fatal(err)
	}
	// 检查连接
	err = client.Ping(ctx, nil)
	if err != nil {
    
		log.Fatal(err)
	}
	fmt.Println("Connected to MongoDB!")
}

断开连接代码

	err = client.Disconnect(ctx)
	if err != nil {
    
		log.Printf(err.Error())
	}
	fmt.Println("Connection to MongoDB closed.")

插入一条数据

//Student 学生结构体
type Student struct {
    
	Name string
	Age  int
	Like string
}
	students := client.Database("school").Collection("student")
	s1 := Student{
    
		Name: "wyh",
		Age:  23,
		Like: "study",
	}
	res, err := students.InsertOne(context.TODO(), s1)
	if err != nil {
    
		log.Println(err.Error())
	} else {
    
		log.Println(res.InsertedID)
	}

插入后的截图
在这里插入图片描述

BSON简介

官方说明:http://bsonspec.org/#/specification
bson包说明:https://godoc.org/github.com/globalsign/mgo/bson
MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON)的二进制表示中。与其他将JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易可靠地处理、排序和比较数据。

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

类型D家族被用来简洁地构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用。D家族包括四类:

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

修改一条数据

	query := bson.D{
    {
    "name", "wyh"}}
	info := bson.D{
    {
    "$set", bson.D{
    {
    "age", 666}}}}
	//此处用的Many,如无必要,尽量用one
	res, err := students.UpdateMany(context.TODO(), query, info)
	if err != nil {
    
		log.Println(err.Error())
	} else {
    
		log.Println(res.ModifiedCount)
	}

再查看一下,age变成了666
在这里插入图片描述
查询一条数据,查询多条的用法和sql的方式一样

	var stu Student
	query := bson.D{
    {
    "name", "wyh"}}
	err = students.FindOne(context.TODO(), query).Decode(&stu)
	if err != io.EOF && err != nil {
    
		log.Fatalln(err)
	}
	log.Println(stu)

结果截图
在这里插入图片描述
删除一条文档

	query := bson.D{
    {
    "name", "wd"}}
	res, err := students.DeleteOne(context.TODO(), query)
	if err != nil {
    
		log.Fatalln(err)
	}
	log.Println(res.DeletedCount)

结果
在这里插入图片描述

用过sql包的应该可以很快上手,这里再简单说明一下
mongo包的函数参数

filter interface{
    }  //一般对应一个bson结构,通常作为条件使用
documents interface{
    } //一般为对应结构体
opts ...*options.xxxxxxx  一般为参数设置,用法如下
//--------------设置最大查询时间,也可以设置其他参数----------
	//fops := options.FindOne().SetMaxTime(time.Millisecond * 200)
	fops := options.FindOne()
	maxtime := time.Second * 3
	fops.MaxTime = &maxtime
	err = students.FindOne(ctx, query, fops).Decode(&stu)

大文件读写

单个文件上传大小最多是16M,这是bson的最大容量,如果想上传大于16m文件,可以用mongo下面的gridfs包

	//打开一个文件读到内存中,也可以直接外存上传
	file, err := ioutil.ReadFile("D:/code/test.mp4")
	if err != nil {
    
		log.Fatalln(err)
	}
	//声明一个桶,嗯~~~,和分布式文件存储呼应上了
	b, err := gridfs.NewBucket(client.Database("school"))
	if err != nil {
    
		log.Fatalln(err)
	}
	//实例一个上传流,并将上面获取的内容写入,“test.mp4”是文件在数据库中的名字,
	us, err := b.OpenUploadStream("test.mp4")
	_, err = us.Write(file)
	if err != nil {
    
		log.Fatalln(err)
	}
	us.Close()
	//创建一个文件
	nfile, err := os.OpenFile("D:/test.mp4", os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
    
		log.Fatalln(err)
	}
	//直接将得到的文件写入刚才创建的文件中。
	_, err = b.DownloadToStreamByName("test.mp4", nfile)
	nfile.Close()

重新连接compass
在这里插入图片描述

  • fs.chunks 是文件具体的存放地点
  • fs.files 是文件的列表

list中可以看见我们的文件,之后上传的文件会被追加进这两个集合中。

尾语

关于mongodb副本集配置参考文档:https://www.cnblogs.com/Joans/p/7680846.html
关于mongodb分片集配置参考文档:https://www.cnblogs.com/wggj/p/8391458.html

未完待续…

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_25490573/article/details/103540311

智能推荐

2017.11.1 三周第三次课-程序员宅基地

3.7 su命令用户切换命令:su"!$":表示上一条命令的最后一个参数查看当前用户命令#whoami#su - 【减号的作用,加上后会初始化当前用户的各种环境变量】#su - aming返回之后的路径,PATH环境变量均是aming用户下的#su aming切换之后,PA..._pan2025

三插头内部结构图_三孔插座内部结构-程序员宅基地

哪些电器需要三孔插座只要不是按照双绝缘设计的低压电器都需要三孔插座。(双绝缘设计的低压电器在铭牌上有“回”样子的标记)2020-08-30三孔插座规格是多少一般般家庭常用的三孔插座有220V-10A、220V-16A。型号有三种: 120型,86型,118型三种。三孔插座上有专用的保护接零(地)插孔,在采用接零保护时,有人常常仅在插座底内将此孔接线柱头与引入插座内的那根零线直接相连,这是极为危险的..._插座内部结构图解

Linux安装loadrunner负载机_loadrunner linux负载机 查看端口-程序员宅基地

1、loadrunner下载地址:http://download.csdn.net/download/intel80586/9542271或者其他资源2、首先用rpm -qa|grep -i c++命令确认服务器是否已经安装了compat-libstdc++-33-3.2.3-61.i386.rpm,若没有下载安装下载地址:http://vdisk.weibo.com/s/akrZxiI7hG..._loadrunner linux负载机 查看端口

WIN2016和WIN10关闭同步主机服务,节省磁盘频繁读取,并关闭自动维护-程序员宅基地

一:“同步主机_XXXXX“的服务项,据说是个没什么用的垃圾同步功能,关闭该服务能有效解决磁盘100%的问题。关闭方法:1、按下WIN+R调出运行,然后输入 regedit 回车;2、在注册表编辑器中定位到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services;3、找到OneSyncSvc、OneSyncSvc_XXXXX、User..._同步主机 55c28

力扣1052.爱生气的书店老板——python解答_python 书店老板-程序员宅基地

题目很好理解,在做的时候我们可以尝试先计算所有的总和,计算过的算为0,之后我们来计算连续X个的哪个总和最大,求和就可以 n = len(customers) res = 0 for i in range(n): if grumpy[i] == 0: res += customers[i] customers[i] = 0 right = X _python 书店老板

linux手动释放内存的方法-程序员宅基地

Linux手动释放缓存的方法Linux释放内存的命令:syncecho 1 > /proc/sys/vm/drop_cachesdrop_caches的值可以是0-3之间的数字,代表不同的含义:0:不释放(系统默认值)1:释放页缓存2:释放dentries和inodes3:释放所有缓存释放完内存后改回去让系统重新自动分配内存。..._linux手动释放内存 的弊端

随便推点

左耳耗子的文章:编程范式体会_左耳朵耗子 编程范式-程序员宅基地

编程范式泛型编程通过使用一种更为通用的方式,用另外的话说就是抽象和隔离,让复让复杂的“世界”变得简单一些。C 语言这样的类型语言来说,首先要拿出来讲的就是抽象类型,这就是所谓的泛型编程。编程范式决定了语言的命运从某种角度上来说,C语言的伟大之处在于--使用C语言的程序员在高级语言的特征智商还能简单地做任何底层上的微观控制。这是C语言的强大和优雅之处。也有人说,..._左耳朵耗子 编程范式

企业微信服务商php环境指令回调URL未响应请求,将无法获取用户事件回调_服务商未响应请求,将无法获取用户事件回调申请校验_千年板蓝根的博客-程序员宅基地

解决问题:企业微信提示服务商未响应请求,将无法获取用户事件回调服务商注册创建应用此步骤忽略,下载phpsdk的代码,可以clone仓库地址:https://gitee.com/shuogesha/weworkapi_php微信配置地址:数据回调地址:你的服务器/sdk目录/callback/callbackverify.php<?phpinclude_once "WXBizMsgCrypt.php";// 假设企业号在公众平台上设置的参数如下$encodingAesKe_服务商未响应请求,将无法获取用户事件回调申请校验

initramfs文件系统的介绍与制作_initramfs的介绍与制作-程序员宅基地

一、什么是initramfs文件系统 initramfs最初的想法是Linus提出的,把cache当作文件系统装载。他在一个叫ramfs的cache实现上加了一层很薄的封装,其它内核开发人员编写了一个改进版tmpfs,这个文件系统上的数据可以写出到交换分区,而且可以设定一个tmpfs装载点的最大尺寸以免耗尽内存。 initramfs就是tmpfs的一个应用。 ramdisk是一_initramfs的介绍与制作

Java学习的第二十四天(JavaSE最终篇_IO流之对象流_Serializable序列化和反序列化)_定义一个类,实现serializable接口,将其对象输出到文本文件中-程序员宅基地

一、需求引入1.要求在不使用对象流的前提下实现如下需求2.需求如下所示:学生信息系统 (a) 假设有20个Student,每个学生有id(学号) name(姓名) age(年龄) className(班级名称) (b) 把20个学生的信息保存到文件中 (c) 从文件中把每个学生的信息都获取处理3.代码演示(结合ArrayList集合类+高效字符缓冲流+增强for+泛型规范)pac..._定义一个类,实现serializable接口,将其对象输出到文本文件中

【Java】File_自由小口袋的博客-程序员宅基地

Windows当中路径是唯一的,如果当前路径已经存在,则创建失败(用mkdir创建一个新的文件夹时,如果路径中已经存在一个同名的无后缀文件,则会创建失败)用createNewFile创建新文件时,如果创建的文件名已存在时,虚拟机不会报错,直接返回false。mkdirs既可以创建单级文件夹,也可以创建多级文件夹,在以后基本上是用此方法创建新文件,但mkdirs方法的底层含有mkdir方法。用createNewFile创建的一定是文件,如果创建时未写文件后缀,则会创建一个没有后缀的文件(文件不一定有后缀名)

推荐文章

热门文章

相关标签