MongoDB数据库(四)高级使用

MongoDB数据库

1. 聚合(aggregate)

  • 聚合是基于数据处理的聚合管道,每个文档通过由一个或多个阶段(stage)组成的管道,可以对每个阶段的文档集进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
    db.集合名称.aggregate({管道:{字段:{表达式}}})

  • 常用表达式
    处理输⼊⽂档并输出,语法:字段:{表达式:'$列名'}

表达式作用
$sum计算总和, $sum:1 表示以⼀倍计数
$avg计算平均值
$min获取最⼩值
$max获取最⼤值
$push在结果⽂档中插⼊值到⼀个数组中
$first根据资源⽂档的排序获取第⼀个⽂档数据
$last根据资源⽂档的排序获取最后⼀个⽂档数据
  • 常用管道:
    ⽂档处理完毕后, 通过管道进⾏下⼀次处理
管道作用
$group将集合中的⽂档分组, 可⽤于统计结果
$match过滤数据, 只输出符合条件的⽂档
$project修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果
$sort将输⼊⽂档排序后输出
$limit限制聚合管道返回的⽂档数
$skip跳过指定数量的⽂档, 并返回余下的⽂档
$unwind将数组类型的字段进⾏拆分
1.1 $group
  • 将集合中的文档分组,可用于统计结果,_id表示分组的依据,使用某个字段的格式为 '$字段'

例如:统计男生女生的总人数

> db.stu.aggregate({$group:{_id:'$gender', counter:{$sum:1}}})
{ "_id" : 1, "counter" : 1 }
{ "_id" : 2, "counter" : 4 }
  • Group by null:将集合中所有文档分为一组

例如:求学生的总人数、平均年龄

> db.stu.aggregate({$group:{_id:null, counter:{$sum:1}, avgAge:{$avg:'$age'}}})
{ "_id" : null, "counter" : 5, "avgAge" : 23.2 }
  • 透视数据
    插⼊值到结果集的数组中

统计不同性别的学生姓名

> db.stu.aggregate({$group:{_id:'$gender', name:{$push:'$name'}}})
{ "_id" : 1, "name" : [ "yh" ] }
{ "_id" : 2, "name" : [ "hx", "my", "xy", "xz" ] }

使用 $$ROOT 可以将文档内容加入到结果集的数组中

> db.stu.aggregate({$group:{_id:'$gender', name:{$push:'$$ROOT'}}})
{ "_id" : 1, "name" : [ { "_id" : ObjectId("5dac0e04f29e62ebc28cc5f7"), "name" : "yh", "age" : 23, "gender" : 1, "hometown" : "qd" } ] }
{ "_id" : 2, "name" : [ { "_id" : ObjectId("5dabdf0cf29e62ebc28cc5f2"), "name" : "hx", "age" : 22, "gender" : 2, "hometown" : "qd" }, { "_id" : ObjectId("5dabdf0ff29e62ebc28cc5f3"), "name" : "my", "age" : 24, "gender" : 2, "hometown" : "wf" }, { "_id" : ObjectId("5dabdf80f29e62ebc28cc5f4"), "name" : "xy", "age" : 24, "gender" : 2, "hometown" : "qd" }, { "_id" : ObjectId("5dac0dddf29e62ebc28cc5f6"), "name" : "xz", "age" : 23, "gender" : 2, "hometown" : "rz" } ] }
1.2 $match
  • 用于过滤数据,只输出符合条件的文档
    用法同标准查询操作

例如:
1.查询年龄大于23的学生

> db.stu.aggregate({$match:{age:{$gt:23}}})
{ "_id" : ObjectId("5dabdf0ff29e62ebc28cc5f3"), "name" : "my", "age" : 24, "gender" : 2, "hometown" : "wf" }
{ "_id" : ObjectId("5dabdf80f29e62ebc28cc5f4"), "name" : "xy", "age" : 24, "gender" : 2, "hometown" : "qd" }

2.查询年龄大于22的男生、女生人数

> db.stu.aggregate({$match:{age:{$gt:22}}}, {$group:{_id:'$gender', counter:{$sum:1}}})
{ "_id" : 1, "counter" : 1 }
{ "_id" : 2, "counter" : 3 }
1.3 $project
  • 修改输入文档的结构,如重命名、增加、删除字段,创建计算结果

例如:
1.查询学生的姓名、年龄

> db.stu.aggregate({$project:{_id:0, name:1, age:1}})
{ "name" : "hx", "age" : 22 }
{ "name" : "my", "age" : 24 }
{ "name" : "xy", "age" : 24 }
{ "name" : "xz", "age" : 23 }
{ "name" : "yh", "age" : 23 }

2.查询男生、女生人数,只输出人数

> db.stu.aggregate({$group:{_id:'$gender', counter:{$sum:1}}}, {$project:{_id:0, counter:1}})
{ "counter" : 1 }
{ "counter" : 4 }
1.4 $sort
  • 将输入文档排序后输出

例如:
1.查询学生信息,按年龄升序

> db.stu.aggregate({$sort:{age:1}})
{ "_id" : ObjectId("5dabdf0cf29e62ebc28cc5f2"), "name" : "hx", "age" : 22, "gender" : 2, "hometown" : "qd" }
{ "_id" : ObjectId("5dac0dddf29e62ebc28cc5f6"), "name" : "xz", "age" : 23, "gender" : 2, "hometown" : "rz" }
{ "_id" : ObjectId("5dac0e04f29e62ebc28cc5f7"), "name" : "yh", "age" : 23, "gender" : 1, "hometown" : "qd" }
{ "_id" : ObjectId("5dabdf0ff29e62ebc28cc5f3"), "name" : "my", "age" : 24, "gender" : 2, "hometown" : "wf" }
{ "_id" : ObjectId("5dabdf80f29e62ebc28cc5f4"), "name" : "xy", "age" : 24, "gender" : 2, "hometown" : "qd" }

2.查询男生、女生人数,按人数降序

> db.stu.aggregate({$group:{_id:'$gender', counter:{$sum:1}}}, {$sort:{counter:-1}})
{ "_id" : 2, "counter" : 4 }
{ "_id" : 1, "counter" : 1 }
1.5 $limit 和 $skip
  • $limit:限制聚合管道返回的文档数
  • $skip:跳过指定数量的文档,并返回余下文档

例如:
1.查询2条学生信息

> db.stu.aggregate({$limit:2})
{ "_id" : ObjectId("5dabdf0cf29e62ebc28cc5f2"), "name" : "hx", "age" : 22, "gender" : 2, "hometown" : "qd" }
{ "_id" : ObjectId("5dabdf0ff29e62ebc28cc5f3"), "name" : "my", "age" : 24, "gender" : 2, "hometown" : "wf" }

2.查询从第三条开始的学生信息

> db.stu.aggregate({$skip:2})
{ "_id" : ObjectId("5dabdf80f29e62ebc28cc5f4"), "name" : "xy", "age" : 24, "gender" : 2, "hometown" : "qd" }
{ "_id" : ObjectId("5dac0dddf29e62ebc28cc5f6"), "name" : "xz", "age" : 23, "gender" : 2, "hometown" : "rz" }
{ "_id" : ObjectId("5dac0e04f29e62ebc28cc5f7"), "name" : "yh", "age" : 23, "gender" : 1, "hometown" : "qd" }
1.6 $unwind
  • 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值

例如:

> db.t2.insert({_id:1,item:'t-shirt',size:['S','M','L']})
WriteResult({ "nInserted" : 1 })
> db.t2.aggregate({$unwind:'$size'})
{ "_id" : 1, "item" : "t-shirt", "size" : "S" }
{ "_id" : 1, "item" : "t-shirt", "size" : "M" }
{ "_id" : 1, "item" : "t-shirt", "size" : "L" }

若现在有这样一个集合:

> db.t3.find()
{ "_id" : 1, "item" : "a", "size" : [ "S", "M", "L" ] }
{ "_id" : 2, "item" : "b", "size" : [ ] }
{ "_id" : 3, "item" : "c", "size" : "M" }
{ "_id" : 4, "item" : "d" }
{ "_id" : 5, "item" : "e", "size" : null }

id = 2, id = 3, id = 5的文档size值为空或者null,此时使用 $unwind 会导致属性值为空的文档被丢失:

> db.t3.aggregate({$unwind:'$size'})
{ "_id" : 1, "item" : "a", "size" : "S" }
{ "_id" : 1, "item" : "a", "size" : "M" }
{ "_id" : 1, "item" : "a", "size" : "L" }
{ "_id" : 3, "item" : "c", "size" : "M" }

此时,若想保留id = 2, id = 3, id = 5的文档,需在 $unwind 中添加 preserveNullAndEmptyArrays 属性:

> db.t3.aggregate({$unwind:{path:'$size', preserveNullAndEmptyArrays:true}})
{ "_id" : 1, "item" : "a", "size" : "S" }
{ "_id" : 1, "item" : "a", "size" : "M" }
{ "_id" : 1, "item" : "a", "size" : "L" }
{ "_id" : 2, "item" : "b" }
{ "_id" : 3, "item" : "c", "size" : "M" }
{ "_id" : 4, "item" : "d" }
{ "_id" : 5, "item" : "e", "size" : null }

2. 索引

2.1 创建索引
  • 语法:db.集合名.ensureIndex({属性:1}),1表示升序, -1表示降序
  • 创建唯一索引db.集合名.ensureIndex({"name":1},{"unique":true})
  • 创建唯一索引并消除重复db.集合名.ensureIndex({"name":1},{"unique":true,"dropDups":true})
  • 创建联合索引 db.t1.ensureIndex({name:1,age:1}) —— 通过多个字段判断文档的唯一性

首先在数据库中创建一个集合,包含100000条数据

> for(i=0;i<100000;i++){db.t12.insert({name:'test'+i,age:i})}

通过一下命令查看执行时间,结果如下:

> db.t12.find({name:'test10000'}).explain('executionStats')
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test1.t12",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"name" : {
				"$eq" : "test10000"
			}
		},
		"winningPlan" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"name" : {
					"$eq" : "test10000"
				}
			},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 74,
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 100000,
		"executionStages" : {
			"stage" : "COLLSCAN",
			"filter" : {
				"name" : {
					"$eq" : "test10000"
				}
			},
			"nReturned" : 1,
			"executionTimeMillisEstimate" : 39,
			"works" : 100002,
			"advanced" : 1,
			"needTime" : 100000,
			"needYield" : 0,
			"saveState" : 782,
			"restoreState" : 782,
			"isEOF" : 1,
			"invalidates" : 0,
			"direction" : "forward",
			"docsExamined" : 100000
		}
	},
	"serverInfo" : {
		"host" : "VM_0_10_centos",
		"port" : 27017,
		"version" : "4.0.13",
		"gitVersion" : "bda366f0b0e432ca143bc41da54d8732bd8d03c0"
	},
	"ok" : 1
}

可以看到"executionTimeMillis" : 74,执行时间为74ms。

现根据name创建索引:

> db.t12.ensureIndex({name:1})
{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

在此之前,_id为默认索引,因此"numIndexesBefore" : 1, "numIndexesAfter" : 2,
再次执行查询命令:

> db.t12.find({name:'test10000'}).explain('executionStats')
{
	"queryPlanner" : {
		"plannerVersion" : 1,
	……
	……
	……
			"inputStage" : {
				"stage" : "IXSCAN",
				"nReturned" : 1,
				"executionTimeMillisEstimate" : 0,
				"works" : 2,
				"advanced" : 1,
	……
	……
	……
		"version" : "4.0.13",
		"gitVersion" : "bda366f0b0e432ca143bc41da54d8732bd8d03c0"
	},
	"ok" : 1
}

可以看到"executionTimeMillis" : 0,执行时间为0ms。

2.2 查看索引
  • 通过db.集合名.getIndexes()查看已经建立的索引
> db.t12.getIndexes()
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",
		"ns" : "test1.t12"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1
		},
		"name" : "name_1",
		"ns" : "test1.t12"
	}
]
2.3 删除索引
  • 通过db.集合名.dropIndex('索引名')删除已经建立的索引

3. 数据的备份和恢复

  • 备份语法:
    mongodump -h dbhost -d dbname -o dbdirectory
    -h: 服务器地址, 也可以指定端⼝号
    -d: 需要备份的数据库名称
    -o: 备份的数据存放位置, 此⽬录中存放着备份出来的数据
  • 恢复语法:
    mongorestore -h dbhost -d dbname --dir dbdirectory
    -h: 服务器地址
    -d: 需要恢复的数据库实例
    –dir: 备份数据所在位置
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值