mongoDB

1.什么是mongoDB

MongoDB是一个基于分布式文件存储的数据库。C++语言编写,为WEB应用提供可扩展的高性能数据存储解决方案。

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

1.1 Docker 启动mongoDB

# 启动mongodb,以用户验证的方式
[root@VM-0-12-centos ~]# docker run -d --name mongod -p 27017:27017 mongo --auth
6db6664c66554230e201ae96f41a890d8630810d5565c8aed632f1a67bd1a467
# 进入mongo中
[root@VM-0-12-centos ~]# docker exec -it mongod /bin/bash
# 打印一下环境变量
root@6db6664c6655:/# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# mongo在环境变量中
root@6db6664c6655:/usr/bin# ls |grep mongo
mongo
mongod
mongodump
mongoexport
mongofiles
mongoimport
mongorestore
mongos
mongosh
mongostat
mongotop
# 这边可以直接通过mongo admin登录到admin数据库中
[root@VM-0-12-centos ~]# docker exec -it mongod mongo admin

#创建用户需要在admin库中执行
> db.createUser({"user":"****","pwd":"****","roles":[{"role":"root","db":"admin"}]})
Successfully added user: {
	"user" : "root",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}
# 返回1表示登录成功
# > db.auth("****","****")
1
# 查看所有用户
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
# 查看所有用户
> show tables
system.users
system.version
#查看所有表
> show tables
system.users
system.version
# 查看所有用户信息
> db.system.users.find()
{ "_id" : "admin.root", "userId" : UUID("f551ff5f-f176-425e-b487-228430223a6e"), "user" : "root", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "9kdct1o92r8HpsZuQsZyaQ==", "storedKey" : "TOZ35SmiYfNcGJ80D7De6FkiQ+4=", "serverKey" : "jlL+egEIRmj4Ivo21kIYHT5APOc=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "nV1HGUD9OoipiaNz6jIs601lLsVyYfq90uWiiQ==", "storedKey" : "vdMT2CuPqPoIIWCwKiryLdvBippGdvTVby2EIq7sTkQ=", "serverKey" : "xBD+gb454BzIdVMeS2e28ofMb2cjZM5wjCv302kRFHQ=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }

使用MongoDB

# 使用数据库,不存在就创建
>use test
# 数据库中插入数据
> db.a.insert({"name":"zhangsan"})
WriteResult({ "nInserted" : 1 })
# 删除数据库
> db.dropDatabase();
{ "ok" : 1 }
# 创建集合
 db.createCollection("item")
{ "ok" : 1 }
# 查看集合
> show tables
item
# capped:如果为true,表示创建固定长度的集合,当达到最大值时,会覆盖之前的文档。该值为true必须指定size
# size: 为固定集合指定一个最大值
# autoinde :如果为true,自动在_id字段创建索引,默认为true
# max 指定集合中文档的最大数量
> db.createCollection("order",{"capped":true,"size":1000,"max":10})
{ "ok" : 1 }
# 集合状态
> db.order.stats()

> db.createCollection("tmp")
{ "ok" : 1 }
# 删除集合
> db.tmp.drop()
true

2.MongoDB文档操作

mongoDB中文档操作是最为重要的部分,指的是多个键及其关联的值有序的放置在一起,也就是我们说的数据。

mongoDB中文档数据和JSON基本一样。所有储存在集合中的数据都是BSON格式(BSON是一种类似于JSON的二进制形式的存储格式,是Binary JSON的简称)。

添加操作

  • 使用db.集合名.insertOne()向集合中添加一个文档,参数一个json格式的文档
  • 使用db.集合名.insertMany()向集合中添加多个文档,参数为json文档数组

// 向inventory集合中添加一个文档
db.inventory.insertOne(
   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
// 向inventory集合中添加多个文档
db.inventory.insertMany([
   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
# 新版本可以直接使用db.集合名.insert()进行添加了
> db.users.save({"name":"zhangsan"})
> db.users.insert({"name":"lisi"})

# 在插入数据的过程中,save和insert没有区别,他们的区别是在更新数据时,save直接更新,insert则会报错。

# 查看数据库中的内容
> db.users.find()
{ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "zhangsan" }
{ "_id" : ObjectId("610562eaea0527cea3a527b1"), "name" : "lisi" }
# 修改内容
> db.users.save({ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "gewei" })
> db.users.find()
# 可以看到数据被修改过来了
{ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "gewei" }
{ "_id" : ObjectId("610562eaea0527cea3a527b1"), "name" : "lisi" }

更新操作

# {} 第一个{}表示匹配所有# "$set" 表示更新的字段,默认只更新第一条db.users.update({},{"$set":{"name":"666"}})# "multi":true 表示更新所有字段,,默认为false。 相同字段更新,不同字段则添加 db.users.update({},{"$set":{"name":"666"}},{"multi":true})WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })> db.users.find(){ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "666" }{ "_id" : ObjectId("610562eaea0527cea3a527b1"), "name" : "666" }{ "_id" : ObjectId("61056825ea0527cea3a527b2"), "age" : "18", "name" : "666" }# 第三个参数:upsert false为只进行更新操作,true为如果匹配不到,执行更新操作# 第四个参数 true 匹配所有字段 false只匹配第一条数据 db.users.update({},{"$set":{"name":"666"}},false,true)# 设置匹配条件使其匹配不到 db.users.update({"name":"biubiu"},{"$set":{"name":"3322"}},true,true)WriteResult({	"nMatched" : 0,	"nUpserted" : 1,	"nModified" : 0,	"_id" : ObjectId("61056ce025f0b93c2b2528ef")})> db.users.find(){ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "666", "didi" : 23 }{ "_id" : ObjectId("610562eaea0527cea3a527b1"), "name" : "666" }{ "_id" : ObjectId("61056825ea0527cea3a527b2"), "age" : "18", "name" : "666" }{ "_id" : ObjectId("61056ce025f0b93c2b2528ef"), "name" : "3322" }# 匹配不到前面的匹配条件也会插入进去> db.users.update({"name":"biu"},{"$set":{"name2":"3322"}},true,true)WriteResult({	"nMatched" : 0,	"nUpserted" : 1,	"nModified" : 0,	"_id" : ObjectId("61056d4625f0b93c2b2528fe")})> db.users.find(){ "_id" : ObjectId("610562b2ea0527cea3a527b0"), "name" : "666", "didi" : 23 }{ "_id" : ObjectId("610562eaea0527cea3a527b1"), "name" : "666" }{ "_id" : ObjectId("61056825ea0527cea3a527b2"), "age" : "18", "name" : "666" }{ "_id" : ObjectId("61056ce025f0b93c2b2528ef"), "name" : "3322" }{ "_id" : ObjectId("61056d4625f0b93c2b2528fe"), "name" : "biu", "name2" : "3322" }
$inc

增加操作,直接添加字段,或者在原来的上面增加

$unset

删除操作

将删除的数据直接操作为1即可,这边可以设为任意值,匹配到就可以删除。

$push

向集合中数组的元素添加一个数组元素,不过滤重复的值,添加时键存在,要求键值类型必须是数组;键不存在,则创建数组类型的键

# 使用$push时,要求添加的键类型必须为字符串

$pop

删除数组中的元素,1最后一个元素,-1为第一个元素

$pull

删除数组中指定元素

# 数组中的值是可以重复的,这时可以用pull'直接删除掉	$pullAll可以删除数组中的数组

$remame

重命名,这边其实是删除了原来的名字,然后创建了一个新的k-v

查询方法

find

查询集合中所有数据findOne查询一条数据,在没有任何条件的情况下,查询第一条

# gt  大于# gte 大于等于# lt  小于# ne  不等于# eq  等于 默认为等于

# $and 和 $or查询

# 在使用and进行查询到 时候,需要键的类型是一样的,单纯的并列查询,不需要使用and

投影

约束查询的结果,在查询的第二个结果上进行设置,设为1表示“真”

# 注意,如果某个字段写1了,除了_id,就不可以再写0	原因:某个字段为1,表示只查询这一个字段,别的字段都为0          相反的一个字段设为0,表示除了这个字段其他的都查询。                    id字段默认查询

使用findOne进行查询,发现对查询结果进行了调整,这是因为findOne后面默认追加了pretty函数

$in

# $nin不在范围内	in和nin查询使用较少
$type

根据类型查询

$type的取值为类型别名,类型别名就是类型的全小写名称。

    number 数值    string 字符串,注意s小写    object 对象    array 数组类型       # db.c1.find({age:{$type:"number"}});
$exists

可以借助$exists判断为空值的文档对象。

db.c1.find({age:{$exists:false}});

# 如果字段为null也表示不存在
正则表达式查询

MongoDB中查询条件也可以使用正则表达式作为匹配约束。正则表达式语法与JavaScript正则表达式语句完全相同。正则内容需要写在 / / 之前。

# 正则选项:    i - 不区分大小写以匹配大小写的情况。    m - 多行查找,如果内容里面不存在换行符号(例如 \n)或者条件上没有(start/end),该选项没有任何效果    x - 设置x选项后,正则表达式中的非转义的空白字符将被忽略。需要$regex与$options语法    s - 允许点字符(即.)匹配包括换行符在内的所有字符。需要$regex与$options语法    i,m,x,s可以组合使用。
sort()
# 对查询结果进行升序或降序排列,1为正序,-1为倒叙

skip()

跳过多少行

limit()

每页有几行

聚合查询

# 对age进行累加> db.user.aggregate([{"$group":{"_id":null,"count":{"$sum":"$age"}}}]){ "_id" : null, "count" : 86 }

对age进行分组,然后计算其和

$match

在分组前对其进行筛选相当于where,放在后面就先分组,然后再筛选

$max和$min和$avg

$push

分组后按照分组数组进行合并,如果希望看到某个列合并之前的所有数据可以使用$push,把分组后同一组的所有值放到一个数组中

按照name进行分组,分组后把age的数据都放入到名称为allAge的数组中

db.c1.aggregate([{$group:{_id:"$name",allAge:{$push:"$age"}}}])
$unwind

$unwind会把数组列进行拆分,原来的document会根据数组属性值个数分为多个document。如果这个数组属性为空,对应document将不被显示(因为document没有数组属性)

删除集合

MongoDB 索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对系统的性能是非常致命的。索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构

在MongoDB中会自动为文档中的_Id(文档的主键)键创建索引,与关系型数据的主键索引类似。

我们可以使用createIndex()或者ensureIndex()函数来为其他的键创建索引。在创建索引时需要指定排序规则。1按照升序规则创建索引,-1按照降序规则创建索引。

# 在创建索引时,需要使用具有dbAdmin或者dbAdminAnyDatabase角色的用户。	语法格式:db.COLLECTION_NAME.createIndex({创建索引的键:排序规则,......},{创建索引的参数(可选参数)})

查看集合索引

我们可以通过getIndexes()或者getIndexSpecs()函数查看集合中的所有索引信息。

语法格式:db.COLLECTION_NAME.getIndexse()

其中getIndexes()可以在Navicat中执行,getIndexSpecs()只能在MongoDB客户端工具中执行。

查看索引键

我们可以通过使用getIndexKeys()函数查看集合的索引键。

注意:此方法在Navicat Pernium 15中无法执行,但是可以mongodb命令行中执行

语法格式:db.COLLECTION_NAME.getIndexKeys();

查看dev集合中的索引键

修改索引

MongoDB没有单独的修改索引函数,如果要修改某个索引,需要先删除旧的索引,再创建新的索引。

删除索引

删除集合中的指定索引

我们可以通过dropIndex()函数来删除指定索引。

语法格式:db.COLLECTION_NAME.dropIndex("索引名称")。

删除集合中的全部索引

我们可以使用dropIndexes()函数删除集合中的全部索引,_id键的索引除外。

语法格式:db.COLLECTION_NAME.dropIndexes()

删除名称为suiyi的索引。删除之前建议使用getIndexes()查看索引信息。

db.c1.dropIndex("suiyi");

重建索引

我可以使用reIndex()函数重建索引。重建索引可以减少索引存储空间,减少索引碎片,优化索引查询效率。一般在数据大量变化后,会使用重建索引来提升索引性能。重建索引是删除原索引重新创建的过程,不建议反复使用。

语法格式:db.COLLECTION_NAME.reIndex()

Q.E.D.


勤俭节约,艰苦奋斗。