mongoDB

什么是NOSQL

NoSQL,其中No指代“non-relational”,仅仅是一个概念,泛指非关系型的数据库

对比RDS

相比于RDS(关系型数据库服务,relational database service),非关系数据库有如下差异

  1. 不保证关系数据的ACID特性(原子、一致、隔离、持久)

  2. NoSQL具有非常高的读写能力,尤其在大数据量下,得益于其无关系性以及数据库的结构简单

  3. 不同于关系型,存在有键值对、列、文档等数据存储类型

  4. 随时可以存储自定义的数据格式,数据模型灵活

  5. 支持的数据结构松散,类似json的bson(二进制JSON)格式,可以存储比较复杂的数据类型

市面产品

目前市场上应用较多的是Redis和mongoDB,下面主要对比一下二者之间的区别

1.内存管理机制

Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。

MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘。

redis比mongo更依赖内存

2.支持的数据结构

Redis 支持的数据结构丰富,包括hash、set、list等。

MongoDB 数据结构比较单一(如json格式),但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富。

3.数据量和性能

当物理内存够用的时候,redis>mongodb>mysql

当物理内存不够用的时候,redis和mongodb都会使用虚拟内存。

实际上如果redis要开始虚拟内存,那很明显要么加内存条,要么你换个数据库了,但是mongodb不一样,只要业务上能保证冷热数据的读写比,使得热数据在物理内存中,mmap的交换较少,mongodb还是能够保证性能。

4.性能

mongodb依赖内存,TPS较高;Redis依赖内存,TPS非常高;性能上Redis优于MongoDB。

5.可靠性

mongodb从1.8版本后,采用binlog方式(MySQL同样采用该方式)支持持久化,增加可靠性;

Redis依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能。

可靠性上MongoDB优于Redis。

6、数据分析

mongodb内置数据分析功能(mapreduce),而Redis不支持。

7.事务支持情况

Redis 事务支持比较弱,只能保证事务中的每个操作连续执行

mongodb目前只支持单文档事务

8.集群

MongoDB 集群技术比较成熟,Redis从3.0开始支持集群

MongoDB简介

MongoDB是一个基于分布式文件存储的数据库,由C++编写,本质上是给数据日益增加的WEB应用提供一个高性能数据存储解决方案。MongoDB是介于RD和NoSQL之间的产品,是NoSQL当中功能最丰富,最像RDS的

mongoDB官方文档地址:https://docs.mongodb.com/manua

支持的数据类型

数据类型 描述
String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean 布尔值。用于存储布尔值(真/假)。
Double 双精度浮点值。用于存储浮点值。
Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array 用于将数组或列表或多个值存储为一个键。
Timestamp 时间戳。记录文档修改或添加的具体时间。
Object 用于内嵌文档。
Null 用于创建空值。
Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID 对象 ID。用于创建文档的 ID。  (每个文档都有)
Binary Data 二进制数据。用于存储二进制数据。
Code 代码类型。用于在文档中存储 JavaScript 代码。
Regular expression

安装

为避免各位同学找不到下载地址,特将下载地址贴出,记得选择社区版

mongoDB官方安装地址https://www.mongodb.com/try/download/community

PS:如果安装企业版需要注册帐号,社区版方便快捷

window版安装

下载window版的安装包,选择最新版,格式为zip包

步骤1:解压

在自己选择的磁盘中创建文件夹mongodb,将下载好的压缩包中的内容移动自其中,此处以E盘为例,其中需要注意的是解压后的文件必须是bin这一级

步骤2:创建日志和数据文件夹

再在对应的data文件夹中创建db文件夹

步骤3:管理员执行控制台命令

管理员身份打开dos命令,之后键入如下指令

#跳转到指令的目录下
cd E:\mongodb\bin

#设置数据文件路径 创建mongodb.log日志文件
mongod --install --dbpath E:\mongodb\data --logpath E:\mongodb\logs\mongodb.log --logappend 

执行成功后对应的MongoDB服务会被创建

步骤4:创建MongoDB为windows服务

因为window下没有fork参数,因此此设置是为了让MongoDB在windows下静默运行,即后台运行

sc create MongoDB binPath= "E:\MongoDB\bin\mongod.exe --service --dbpath E:\mongodb\data --logpath=E:\mongodb\log\mongodb.log --logappend"

PS:如果提示已经创建,则忽略此步骤

步骤5:启动MongoBD服务

net start mongodb 

如果想关闭服务,可以使用

net stop mongodb 

步骤6:登录MongoDB

mongo

如果登录成功,会提示如下界面

#步骤7 配置bin路径到环境变量path路径

此步骤省略,与以前JDK配置类似,只需要将MongoDB的安装路径下的bin路径复制到指定的环境变量path中即可

linux版安装

linux后期讲到服务器部署时专门进行讲解,后期讲解的linux为常用的centOS,此处先放出mongoDB的linux版安装所需要的一些指令

步骤1:通过wget指令远程下载mongodb,通过copylink的方式复制下载地址

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.1.tgz

步骤2:解压对应的压缩包

tar -zxvf mmongodb-linux-x86_64-rhel80-4.4.1.tgz

步骤3:拷贝解压后的文件到指定路径

mv mongodb-src-r4.4.1  /usr/local/mongodb

步骤4:配置mongoDB变量(与以前JDK配置一样)

#案例
export PATH=mongodb安装地址/bin:$PATH

export PATH=/usr/local/mongodb/bin:$PATH

步骤5:创建数据库目录

MongoDB 启动后会初始化以下两个目录

  • 数据存储目录:/var/lib/mongodb
  • 日志文件目录:/var/log/mongodb

我们在启动前可以先创建这两个目录并设置当前用户有读写权限:

sudo mkdir -p /user/local/mongodb/data /user/local/mongodb/logs #创建数据和日志文件
sudo chown `jish` /var/lib/mongodb   # 设置权限
sudo chown `jish` /var/log/mongodb   # 设置权限

步骤6:启动 Mongodb 服务

/user/local/mongodb/bin/mongod --dbpath=/user/local/mongodb/data --logpath=/user/local/mongodb/logs/mongod.log --logappend --port=27017 --fork

步骤7:打开mongoDB

/user/local/mongodb/bin/mongodb

如果打开后发现有启动成功(sucessfully)字样,则证明启动成功

权限配置

与之前的mysql一样,可以创建某个用户并为其设置对应的数据库权限,具体的设置语法如下

创建角色语法

use 数据库名
db.createUser({
	"user":"登录帐号",
	"pwd":"登录密码",
	"roles":[{
		role:"内置角色",
		db:"所属数据库"
	}]
})

角色权限


内置角色:
1. 数据库用户角色:read、readWrite;
2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
4. 备份恢复角色:backup、restore;
5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
6. 超级用户角色:root 
7. 内部角色:__system
// 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)

部分角色解释说明:
read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限。

操作步骤

1.创建角色

use admin
db.createUser({
	"user":"sa",
	"pwd":"sa",
	"roles":[{
		role:"root",
		db:"admin"
	}]
})
#验证用户是否插入成功
db.system.users.find().pretty()

2.卸载mongoDB服务

#管理员身份运行
mongod --remove

3.重新安装mongoDB服务

mongod --install --dbpath E:\mongodb\data --logpath E:\mongodb\logs\mongodb.log --logappend --auth

4.服务重启,登录

net start mongodb
#mongo直接登录
mongo
#show dbs 发现发现并没有发现数据库
show dbs 

登录方式

方式一

mongo [IP:端口号/数据库名] -u用户名 -p密码

案例

# mongo 127.0.0.1:27017/admin -usa -psa
#不写默认进入的是admin库
mongo -usa -psa

方式二

use admin
db.auth("sa","sa")

多用户权限管理案例

此处演示一个案例,创建2个库,并分别对2个库创建对应的用户,进行相应的权限设置

添加数据

use myTest
for(var i = 1; i <= 3; i++){
	db.fang.insert({"name":"fang"+i,"age":i})
}

创建2个用户

db.createUser({
	"user":"zz",
	"pwd":"zz",
	roles:[{
		"role":"read",
		"db":"myTest"
	}]
})

db.createUser({
	"user":"jj",
	"pwd":"jj",
	roles:[{
		"role":"readWrite",
		"db":"myTest"
	}]
})

验证是否有效

use admin
db.system.users.find().pretty()

登录zz帐号,往myTest中添加数据,发现被拒绝

mongo 127.0.0.1:27017/myTest -uzz -pzz

#下列写法均可
# mongo 127.0.0.1:27017/myTest -u zz -p zz
# mongo localhost:27017/myTest -u zz -p zz

删除用户

db.dropUser("用户名")  根据用户名删除指定用户
db.dropAllUser()  删除所有用户

注意,需要使用拥有权限的用户进行删除处理,如一开始添加的root权限用户,如果实在删不掉,就用删除所有用户的方式

常用语法

数据库

展示数据库

这个与之前学习的其他数据库一样,系统会默认提供3个库

show databases

选择数据库

也是与之前相同的语法,只不过有一点不同的是,选择不存在的数据库,也不会报错,如果用户在选择的这个不存在的库A中去创建数据,则系统会隐式创建库A(通常也是用隐式创建的方式

use stusys

删除数据库

删除指定数据库与以前有点不同

use 指定数据库
db.dropDatabase() 删除指定数据库

集合

集合是Mongodb中数据的存储模式,类似集合中

查看集合

show collections

创建集合

db.createCollection('集合名')

案例

db.createCollection('myCollection')

注意

实际上,在MongoDB中也无需显示创建集合,与选择数据库时隐式创建相同,往一个指定集合中添加数据,也可以隐式创建该集合

删除集合

需要注意的是,需要指定集合名称

db.集合名.drop()

CRUD

新增

db.集合名.insert(集合内容,格式与json类似)
案例

注意,此案例隐式创建了数据库test以及集合my1

use test
db.fang2.insert({name:"fanglaoc",age:"18"})
for(var i = 0; i < 100 ; i++){
	db.fang.insert({name:"fang"+i,age:i});
}
补充
1.默认UUID

插入时默认添加的_id(UUID)也可以在插入数据的同时一并添加,但通常不需要手动覆盖,默认提供的UUID即可

db.fang2.insert({_id:"1",name:"fanglaoc",age:"18"})
2.多行插入

通过上面的插入案例可以得知,实际上插入的数据为json格式数据,对于多条数据只需要定义json格式的数组即可

db.fang2.insert([
{name:"fang",age:"13"},
{name:"zhi",age:"14"},
{name:"jian",age:"15"}
])
3.JS支持

mongoDB本身也支持部分js语法,比如也可以通过for循环进行遍历插入

for(var i = 1; i <= 10; i++){
	db.fang2.insert({name:"fang"+i,age:i});
}

查找

基础案例

通过该指令可以查找集合名下的所有内容

db.集合名.find()

注意:在插入一条数据后,mongodb会默认为我们新增一个UUID作唯一表示,关于UUID的组成,实际上是由 :时间戳(4位)+ 机器码(3位)+ PID(2位)+ 计数器(3位)

查找进阶
语法
db.集合名.find(条件[,查询列])
条件语法

注意:此处单引号 双引号均可,只需要记住和json格式相似即可

查询所有数据  {}或者不写
查询指定条件如姓名 {name:"fang"}    
多条件查询 {name:"fang",age:"18"}
模糊查询(实际上就通过正则表达式来实现)
方式1:{name:{$regex:"fang"}}
方式2:{name:/fang/}
范围区间查询: 需要结合运算符,以前学过的&lt;&gt;但需要注意此处使用的是$lt $gt
in查询 {age:{$in:[3,5,18]}}
db.fang.find({age:{$in:[1,10,99]}})
条件案例

1、单条件查询
image-20201003191118937

2、复合条件查询

image-20201003191209344

3、模糊查询

image-20201003190900464

4、范围区间查询

范围区间查询需要使用到运算符,以下为常用的运算符

  • $gt 大于
  • $gte 大于等于
  • $lt 小于
  • $lte 小于等于
  • $ne 不等于
  • $in in区间
  • $nin 不在in区间

案例

查询年龄大于8岁的用户

db.fang2.find({age:{$gte:8}})

image-20201003192417349

查询年龄在3到10岁之间的用户

db.fang2.find({
	age:{$gte:3,$lte:10}
})

5、in查询

db.fang2.find({age:{$in:[1,3,18]}})

如果查询的为"“,则表示查询的为字符串,如果不带”",则表示查询的为数字类型

查询列

需要注意的是,0和1分别表示的是排除指定列和包含指定列

db.集合名.find({条件},{age:0})
db.集合名.find({条件},{age:1})
查找结果美化

对于查找后的json格式数据,如果希望格式化,可以使用pretty()

db.fang2.find().pretty()

修改

语法
--较少使用,本质为替换
db.集合名.update(条件,新数据) 
--较多使用
db.集合名.update(条件,{修改器:{键:值}})
db.集合名.update(条件,新数据[,是否新增(默认false),是否修改多条(默认false)])
案例
db.集合名.update(条件,新数据)

将年龄为3的用户名改为jojo

db.fang2.update({age:3},{name:"jojo"})
db.集合名.update(条件,{修改器:{键:值}})

常见修改器

  • $inc 递增 减少用负数 如 $inc:
  • $rename 重命名列
  • $set 修改列值
  • $unset 删除列
db.fang2.update({age:4},{$set:{name:"jojo"}})

多个修改器复合使用

db.集合名.update(条件,{
	修改器:{键:值},
	修改器:{键:值},
	修改器:{键:值}
})

将name为jojo的行的name属性改为nickname,年龄增加12岁

db.fang2.update({name:"jojo"},{
	$inc:{age:12},
	$rename:{name:"nickname"}
})
db.集合名.update(条件,新数据[,是否新增(默认false),是否修改多条(默认false)])

是否新增

如果没有符合条件的数据行,则默认为你创建一条数据

db.fang2.update({age:11},{$set:{age:11,name:"fang11"}},true)

本身虽然没有age11的数据,但为我们自动创建了

小实验:如果更新一条不存在的数据,并且采用$inc的方式,可以发现一样会为我们创建一条新的,并且是基于原有数据12去加1

db.fang2.update({age:12},{$inc:{age:1}},true)

如果不以age为条件,此时$inc设置的age,会变为新建数据行的初始值

db.fang2.update({name:"fang12"},{$inc:{age:1}},true)

是否修改多条

这实际上是mongoDB的保护机制,避免用户批量修改过多数据导致数据出错,因此每次更新都是默认更新满足条件的1条,如果将其设置为true,则可以修改所有

将名字包含fang的所有数据的年龄都设置为100

db.fang2.update({name:/fang/},{$set:{age:100}},false,true)

可以发现所有包含fang的行年龄都变为100

删除

语法

默认为false,即删除符合所有条件的数据行

db.fang2.remove(条件[,是否删除一条])
案例
--删除名字自中带有fang的,删除一条(较少使用)
db.fang2.remove({name:/fang/},true)
--删除名字自中带有fang的,删除全部
db.fang2.remove({name:/fang/})

其他函数

skip和limit

当我们使用分页查询时,在mysql中使用的是如下语法

select * from student limit [index,]columns
index表示起始索引,columns表示每次查询的总行数

select * from student limit 5,5
查询所有学生信息,从第6条数据开始,每次查询出5条

但是在mongoDB中,limit只有一个参数,因此想要实现分页功能,需要借助skip和limit一起实现

案例集合:
for(var i = 1; i <= 20; i++){
   db.fang3.insert({name:"fanglaoc",age:i})
}

单独使用limit()函数,则表示从第1条数据开始,查找符合条件的前5条

db.fang2.find().limit(5)
等价于db.fang2.find().skip(0).limit(5)

如果希望每页5条,查找第4页(最后1页),可以分析得知,第16条开始,下标为15

#此公式和当时讲解的mysql分页的公式一样
起始下标 = (当前页数 - 1) * 每页分页  
db.fang3.find().skip(15).limit(5)

sort

在以前mysql,我们对于查询到的数据进行升序排序时,使用的是order by关键字,而在mongoDB中,我们使用的是sort函数

db.fang3.find().sort({age:1}).skip(15).limit(5)

sort中,sort({age:1})表示按年龄升序排序,sort({age:-1})表示按年龄降序排序

但此处可以发现一个问题,如果多个函数,sort,limit,skip一起使用时,在降序时会发现结果并不是20 19… 16,这是因为mongoDB中 skip、limit、sort有优先级

顺序为:sort>skip>limit

问题解决

利用下面要讲解的 aggregate(聚合函数),利用其管道流的性质,可以解决优先级问题

db.getCollection(‘fang3’)是获取fang3这个集合,然后利用aggregate聚合函数的特性,设置函数的优先级

注意:db.getCollection(‘fang3’)和db.fang3等价

#db.getCollection('fang3').aggregate([{$skip:15},{$limit:5},{$sort:{age:-1}}]);
db.fang3.aggregate([{$skip:15},{$limit:5},{$sort:{age:-1}}]);

db.jojo.aggregate([
	{$skip:5},
	{$limit:5},
	{$sort:{age:-1}}
]) 

聚合函数(aggregate [ˈæɡrɪɡət , ˈæɡrɪɡeɪt])

MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等)

对于一些函数的默认优先级不方便使用的情况,可以利用aggregate的管道流的性质,将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理,进而各类函数优先级问题

语法
db.集合名称.aggregate([
	{管道:{表达式}}
	...
])
管道
$group 将集合中的文档分组,可用于统计结果
$match 用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作
$sort 将输入文档排序后输出
$skip 在聚合管道中跳过指定数量的文档,并返回余下的文档
$limit 用来限制MongoDB聚合管道返回的文档数

#较少使用
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
$geoNear:输出接近某一地理位置的有序文档
常用表达式
$sum 计算总和 #其中$sum:1与count等价,表示数量统计
$avg 计算平均值
$min 获取集合中所有文档对应值得最小值
$max 获取集合中所有文档对应值得最大值

#较少使用
$push 在结果文档中插入值到一个数组中
$addToSet 在结果文档中插入值到一个数组中,但不创建副本
$first 根据资源文档的排序获取第一个文档数据
$last 根据资源文档的排序获取最后一个文档数据
案例

示例数据

use test
db.fang4.insert({name:"丽丽",age:15,gender:"女"})
db.fang4.insert({name:"花花",age:15,gender:"女"})
db.fang4.insert({name:"咪咪",age:10,gender:"男"})
db.fang4.insert({name:"帅帅",age:10,gender:"男"})
db.fang4.insert({name:"兵兵",age:20,gender:"男"})
案例一

统计fang4集合中的男女的人数

group管道中id表示要根据哪一列进行分组,其中gender列在使用时,需要添加美元符,即group管道中,_id表示要根据哪一列进行分组,其中gender列在使用时,**需要添加美元符**,即gender,如果不希望分组则将 _id的值设置为null

count为自己定义的名称,{$sum:1}则等价于计数函数count

db.fang4.aggregate([
	{
		$group:{
            _id:"$gender",
            count:{$sum:1}
		}
	}
])
案例二

统计fang4集合中的男女的年龄总和

db.fang4.aggregate([
	{
		$group:{
            _id:"$gender",
            count:{$sum:"$age"}
		}
	}
])
案例三

统计fang4集合中年龄最大的女性

match管道用于匹配数据,match管道用于匹配数据,group管道用于数据分组,从逻辑上来讲,是先筛选出指定类型的数据,再进行分组,因此match管道放在group管道前面

db.fang4.aggregate([
	{
		$match:{
			gender:"女"
		}
    },
    {
		$group:{
			_id:null,
			min:{$max:"$age"}
		}
	}
])

db.fang4.aggregate([
	{
		$match:{
			age:{$gte:0,$lt:20}
		}
	},
	{
		$group:{
			_id:"$gender",
			total:{$sum:1},
			avg:{$avg:"$age"}
		}
	}
])
案例四

统计fang4集合中学小于20岁的男女学生总数和平均年龄

db.fang4.aggregate([
	{
		$match:{
			age:{$gte:0,$lt:20}
		}
	},{
		$group:{
			_id:"$gender",
			count:{$sum:1},
			avg:{$avg:"$age"}
		}	
	}
])
案例五

按照指定要求进行分组查询,以fang3集合为例(20条数据的那个),每页数量为5条数据,从第2页开始,查询满足年龄在10岁以上(含10岁)的学生信息,并按照年龄降序排序

db.fang3.aggregate([
	{$match:{age:{$gt:10}}},
	{$skip:5},
	{$limit:5},
	{$sort:{age:-1}}
]);

索引

此处的索引与mysql相同,用于加快的检索速度,本质上的数据结构为 排序二叉树

优点

毋庸置疑,减少CPU损耗和数据库成本,大大加快检索速度,(尤其对于经常检索的条件列,因此一般索引就加在这样的列上)

缺点

  1. 索引本身占据一定的空间
  2. 过多索引一定程度会影响SQL语句(主要是新增、修改、删除)执行效率,因为这些操作需要更新索引

创建索引

语法

db.集合名.createIndex(待创建索引的列[,额外选项])

参数解释

待创建的列:{键:1...,键:-1}
1表示升序 -1表示降序 {id:1}创建id索引并索引按照升序方式存储
额外选项可以设置索引名以及唯一索引

查看所有索引

语法

db.集合名.getIndexes()

删除索引

语法

删除指定索引
db.集合名.dropIndex(集合名)
全部索引删除
db.集合名.dropIndexes()

案例

0、基础数据准备

use indexTest
for(var i = 1; i <= 20000; i++){
	db.fang.insert({name:"fang"+i,age:i});
}

1、普通索引

如果用户经常对用户名使用模糊查询,在这样的场景下可以为name设置索引

db.fang.createIndex({name:1})

2、索引删除

如果对于上面的索引不想要了,可以删除对应的索引

db.fang.dropIndex("name_1")

3、创建自定义名索引

db.fang.createIndex({"name":1},{"name":"fang_name_index"})

4、复合索引

与以前学习的复合主键类似,复合索引即表示为多个列创建索引,如果有些查询带有多个条件时可以使用

db.fang.createIndex({name:1,age:-1},{name:"name_age_index"})

5、唯一索引

与以前讲解的主键约束一样,为某一列定义主键实际上就是为主键列设置一个索引,并且添加一个唯一约束,唯一索引的主要作用是避免列插入重复的值

db.fang.createIndex({name:-1},{name:"name_index","unique":"name"})

如果插入重复的或者之前的数据列存在重复数据想添加唯一索引,都会引发错误冲突

索引效率校验

对比下性能差距,此处可以通过explain函数实现对某个sql的性能检测

其中executionStats中executionStages的属性值有几个值,如:

  • COLLSCAN 全表扫描
  • IXSCAN 索引扫描
  • FETCH 根据索引检索指定document

语法

db.集合名.find(条件).explain("executionStats")

案例

添加索引情况

db.fang.find({age:1}).explain("executionStats")

不添加索引情况

同样的执行语句,把对应的索引进行删除

db.fang.find({age:1}).explain("executionStats")

可视化工具

mongoDB常用的可视化工具有很多,此处使用的是NoSQLBooster for MongoDB

下载地址:https://www.mongobooster.com/downloads

技术选型

对于mongoDB的使用场景其实有很多,当然在性能上考虑很多公司还是会考虑用redis,但在某些场合下,mongoDB的性能会比redis快,以下场景可以考虑使用mongoDB

1、公司业务不要求事务且sql语句简单,无需过多繁琐join语句

2、数据模型不确定但又想要快速迭代

3、数据高读写速度

4、项目需要大量的地理位置查询、文本查询

5、项目本身需要较大数据存储(硬盘是mongo的一大优势)