MongoDB进阶:查询优化、账户权限设置、aggregate聚合管道查询!!!

MongoDB大数据查询优化

索引基础

索引是对数据库表中的一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更快。MongoDB的索引几乎与传统关系型数据库一模一样,这其中也包括一些基本的查询优化技巧。

  • 下面是创建索引的命令
db.user.ensureIndex({"username":1});
  • 获取当前集合的索引
db.user.getIndexes()
  • 删除索引的命令是
db.user.dropIndex({"username":1})

比较有无创建索引查询速度

  1. 首先进入数据库,使用for循环创建80000条数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j0mm2Xhr-1598607721424)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/1.jpg)]

  1. 使用如下语句显示查询时间:
db.dog.find({"dogName":"xiaohua50000"}).explain("executionStats")

在这里插入图片描述
在这里插入图片描述

  1. 创建索引:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mb1WqZqR-1598607721428)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/4.jpg)]

  1. 再次换一个数据查询:

在这里插入图片描述
在这里插入图片描述

我们可以看到创建索引后查询速度变快了很多

  1. 删除索引,再查看我们的查询时间:

在这里插入图片描述
在这里插入图片描述

复合索引

db.dog.ensureIndex({"dogName":1,"age":-1}) //1表示升序,-1表示降序
  • 该索引被创建后,基于dogName和age的查询将会用到该索引,或者是基于dogName的查询也会用到该索引。
  • 但是只是基于age的查询将不会用到该复合索引。因此可以说,如果想用到复合索引,必须在查询条件中包含复合索引的前N个索引列。
  • 然而如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调整该顺序,以便使复合索引可以为查询所用。如:
db.dog.find({"age":30,"dogName":"stephen"})

唯一索引

  • 下面的示例将创建唯一索引,如:
db.dog.ensureIndex({"age":1},{"unique":true})
  • 如果再次插入age重复文档时,MongoDB将会报错,以提示插入重复键,如:
db.dog.insert({"age":100001})
db.dog.insert({"age":100001})

E11000 duplicate key err index:dog.dog.$age_1 dup key:{:100001.0}

MongonDB账户权限配置

  1. 创建超级管理员:
use admin

db.createUser({
	user:'admin',
	pwd:'123456',
	roles:[{role:'root',db:'admin'}]
})
  1. 修改MongoDB数据库配置文件。
  2. 重启mongdb服务。
  3. 用超级管理员管理账户连接数据库。
mongo admin -u 用户名 -p 密码

mongo 192.168.1.200:27017//test -u username -p password   //远程
  1. 给aniu数据库常见一个用户,只能访问aniu不能访问其他数据库。
use aniu

db.createUser({
	user:"aniuadmin",
	pwd:"123456",
	roles:[{role:"dbOwner",db:"aniu"}]
})

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XUCMFDrd-1598607721433)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/9.jpg)]

MongoDB账户权限配置中常用的命令

1、show users;   查看当前库下的用户
2、db.dropUser("aniu111");   删除用户
3、db.updataUser("admin",{pwd:"password"});   修改用户密码
4、db.auth("admin","password");   密码认证

数据库角色

  1. 数据库用户角色:read、readWrite;
  2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
  3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
  4. 备份恢复角色:backup、restore;
  5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase;
  6. 超级用户角色:root

连接数据库的时候需要配置账户密码

const url = 'mongodb://admin:123456@localhost:27017';

关系型数据库中表与表的关系

一对一的关系

  • 例如:一个人对应一个唯一的身份证号,即为一对一关系。

一对多的关系

  • 例如:一个班级有多个学生,一个学生只能属于一个班级。

多对多的关系

  • 一个学生可以选多门课程,而同一门课程可以被多个学生选修,彼此的对应关系即是多对多关系。

MongoDB高级查询aggregate聚合管道

MongoDB聚合管道(Aggregation Pipeline)

  • 使用局和管道可以对集合中的文档进行变换和组合。

  • 语法

    aggregate() 方法的基本语法格式如下所示:

    db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
    
  • 实际项目中用于:表的关联查询、数据的统计。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-alMSLYfe-1598607721433)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/10.jpg)]

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

下表展示了一些聚合的表达式:

表达式描述实例
$sum计算总和。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}])
$avg计算平均值db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}])
$min获取集合中所有文档对应值得最小值。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}])
$max获取集合中所有文档对应值得最大值。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}])
$push在结果文档中插入值到一个数组中。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}])
$addToSet在结果文档中插入值到一个数组中,但不创建副本。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}])
$first根据资源文档的排序获取第一个文档数据。db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}])
$last根据资源文档的排序获取最后一个文档数据db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}])

测试

模拟数据:

> db.order.find()
{ "_id" : ObjectId("5f48c087f6f819aca2112b34"), "order_id" : "1", "uid" : 10, "trade_no" : "111", "all_price" : 100, "all_num" : 2 }
{ "_id" : ObjectId("5f48c0b3f6f819aca2112b35"), "order_id" : "2", "uid" : 7, "trade_no" : "222", "all_price" : 90, "all_num" : 2 }
{ "_id" : ObjectId("5f48c194f6f819aca2112b36"), "order_id" : "3", "uid" : 9, "trade_no" : "333", "all_price" : 20, "all_num" : 6 }

> db.order_item.find()
{ "_id" : ObjectId("5f48c1e7f6f819aca2112b37"), "order_id" : "1", "title" : "商品鼠标1", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c1f6f6f819aca2112b38"), "order_id" : "1", "title" : "商品键盘2", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c208f6f819aca2112b39"), "order_id" : "2", "title" : "牛奶", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c216f6f819aca2112b3a"), "order_id" : "2", "title" : "酸奶", "price" : 40, "num" : 1 }
{ "_id" : ObjectId("5f48c231f6f819aca2112b3b"), "order_id" : "3", "title" : "矿泉水", "price" : 2, "num" : 5 }
{ "_id" : ObjectId("5f48c242f6f819aca2112b3c"), "order_id" : "3", "title" : "毛巾", "price" : 10, "num" : 1 }

在我们的数据库中建立一个叫order的表以及一个叫order_item的表。加入以上的数据。

$project

修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RvFIHqgN-1598607721434)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/11.jpg)]

$match

用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}} 
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1fzvnk3d-1598607721435)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/12.jpg)]

$group

将集合中的文档分组,可用于统计结果。

db.order_item.aggregate([
	{
		$group:{_id:"$order_id",total:{$sum:"$num"}}
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nEYHwgph-1598607721436)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/13.jpg)]

db.order_item.aggregate([
	{
		$group:{_id:"$order_id",total:{$sum:"$price"}}
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goHo5ZsY-1598607721437)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/14.jpg)]

$sort

将输入文档排序后输出。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tl0aPcI0-1598607721438)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/15.jpg)]

$limit

用来限制MongoDB聚合管道返回的文档数。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	},
	{
		$limit:1
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXVg8zIy-1598607721439)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/16.jpg)]

$skip

在聚合管道中跳过指定数量的文档,并返回余下的文档。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	},
	{
		$skip:1
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YxaoBUHx-1598607721439)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/17.jpg)]

$lookup 表关联

db.order.aggregate([
	{
		$lookup:
			{
			from:"order_item",
			localField:"order_id",
			foreignField:"order_id",
			as:"items"
			}
	}
])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGATfXh7-1598607721440)(/Users/mac/Desktop/MarkDown /nodejs笔记/MongoDB/MongoDB笔记二/18.jpg)]

得到的数据:

{
	"_id": ObjectId("5f48c087f6f819aca2112b34"),
	"order_id": "1",
	"uid": 10,
	"trade_no": "111",
	"all_price": 100,
	"all_num": 2,
	"items": [{
		"_id": ObjectId("5f48c1e7f6f819aca2112b37"),
		"order_id": "1",
		"title": "商品鼠标1",
		"price": 50,
		"num": 1
	}, {
		"_id": ObjectId("5f48c1f6f6f819aca2112b38"),
		"order_id": "1",
		"title": "商品键盘2",
		"price": 50,
		"num": 1
	}]
} 

{
	"_id": ObjectId("5f48c0b3f6f819aca2112b35"),
	"order_id": "2",
	"uid": 7,
	"trade_no": "222",
	"all_price": 90,
	"all_num": 2,
	"items": [{
		"_id": ObjectId("5f48c208f6f819aca2112b39"),
		"order_id": "2",
		"title": "牛奶",
		"price": 50,
		"num": 1
	}, {
		"_id": ObjectId("5f48c216f6f819aca2112b3a"),
		"order_id": "2",
		"title": "酸奶",
		"price": 40,
		"num": 1
	}]
} 

{
	"_id": ObjectId("5f48c194f6f819aca2112b36"),
	"order_id": "3",
	"uid": 9,
	"trade_no": "333",
	"all_price": 20,
	"all_num": 6,
	"items": [{
		"_id": ObjectId("5f48c231f6f819aca2112b3b"),
		"order_id": "3",
		"title": "矿泉水",
		"price": 2,
		"num": 5
	}, {
		"_id": ObjectId("5f48c242f6f819aca2112b3c"),
		"order_id": "3",
		"title": "毛巾",
		"price": 10,
		"num": 1
	}]
}

即将表orde_item数据关联到表order中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值