MongoDB索引操作
索引
索引就是提升数据库检索性能的手段
MongoDB数据库里面有两种索引的创建:自动创建,手工创建
范例:简单的集合
db.students.drop(); db.students.insert({"name":"张三","sex":"男","age":19,"score":89,"address":"松江区"}) db.students.insert({"name":"李四","sex":"女","age":20,"score":59,"address":"青浦区"}) db.students.insert({"name":"王五","sex":"女","age":21,"score":99,"address":"浦东新区"}) db.students.insert({"name":"赵六","sex":"男","age":20,"score":100,"address":"朝阳区"}) db.students.insert({"name":"孙七","sex":"男","age":19,"score":0,"address":"海淀区"}) db.students.insert({"name":"王八","sex":"女","age":19,"score":89,"address":"宝山区"}) db.students.insert({"name":"刘九","sex":"男","age":20,"score":69,"address":"长宁区"}) db.students.insert({"name":"钱十","sex":"女","age":21,"score":79,"address":"松江区"}) |
|
此时在studnets集合上并没有去设置任何的索引,那么下面通过getIndexes()函数来观察在students集合里面需要已经存在的索引内容。
范例:查询默认状态下的students集合的索引内容
db.students.getInexes(); |
现在发现会存在以“_id”列 1 表示升序。名字 _id_。创建自己的索引如下的语法
索引创建:db.集合名称.ensureIndex({列:1})
设置1表示升序,-1表示降序
范例:创建一个索引
db.students.ensureIndex({"age":-1}); |
此时没有设置索引名字,所以名字是自动命名的。命名规范:“字段名称_排序模式”
范例:针对于当前的age字段上的索引做一个分析
db.students.find({"age":19}).explain(); |
此时的查询使用了索引的技术,下面不使用索引
范例:针对score字段查询
db.students.find({"score":{"$gt":60}}).explain(); |
此时score字段上并没用设置索引,当前索引形式就变为了全集合扫描
但是如果说,现在换一种形式年龄和成绩一起执行判断查询?
db.students.find({"$or":[{"age":{"$gt":19}},{"score":{"$gt":60}}]}).explain(); |
虽然age字段有索引,因为score没有索引,依旧是全集合扫描
所以创建一个复合索引
db.students.ensureIndex({"age":-1,"score":-1},{name:"age_index_score_01"}); |
范例:默认使用索引
db.students.find({"age":19,"score":89}).explain(); |
但是如果换到了条件之中:
db.students.find({"$or":[{"age":{"$gt":19}},{"score":{"$gt":60}}]}).explain(); |
现在发现并没有使用索引,所以这个时候看能否强制使用一次索引。hint()强制使用索引操作。
范例:强制使用索引
db.students.find({"$or":[{"age":{"$gt":19}},{"score":{"$gt":60}}]}).hint({"age":-1,"score":-1}).explain(); |
如果正常来说,这个代码根本就不能调用索引执行,所以就是用hint()函数来强制MongoDB使用一次索引,由于age和score已经设置了复合索引,所以就使用复合索引
如果设置了过多的索引,实际上会导致性能的下降,那么就可以删除索引。
范例:删除一个索引
db.students.dropIndex({"age":-1,"score":-1}); |
范例:清楚全部索引
db.students.dropIndexes(); |
只能删除自定义的索引
唯一索引
唯一索引的主要目的是在某一个字段上,使该字段的内容不重复。
范例:创建唯一索引
db.students.ensureIndex({"name":1},{"unique":true}); |
在内容字段上的内容绝对不允许重复,如果加入重复的索引(name)会出现以下错误提示信息
E11000 duplicate key error collection: mldn.students index: name_1 dup key: { : \"张三\" } |
过期索引
在一些程序站点会出现若干秒之后信息被删除的情况,例如:手机的信息验证码,在MongoDB里实现过期索引,但这个时间往往不可能准确
范例:设置过期索引
db.phones.ensureIndex({"time":1},{expireAfterSeconds:10}); |
范例:在一个phones集合里面设置一个过期索引
如果要想实现过期索引,需要保存一个时间信息
db.phones.insert({"tel":110,"code":110,"time":new Date()}); db.phones.insert({"tel":111,"code":111,"time":new Date()}); db.phones.insert({"tel":112,"code":112,"time":new Date()}); db.phones.insert({"tel":113,"code":113,"time":new Date()}); db.phones.insert({"tel":114,"code":114,"time":new Date()}); |
等到10秒后永远不准所保存的临时数据就会消失。
全文检索
在MongoDB里面实现了非常简单的全文检索
范例:先添加数据
db.news.insert({"title":"mldn mldnjava lxh gyh","content":"gyh"}); db.news.insert({"title":"mldn mldnjava lxh","content":"java"}); db.news.insert({"title":"gyh","content":"sfq"}); db.news.insert({"title":"gyh","content":"gry"}); db.news.insert({"title":"sfq","content":"gry"}); |
范例:设置全文检索
db.news.ensureIndex({"title":"text","content":"text"}); |
范例:实现数据的模糊查询
如果要想表示出全文检索,则使用“$text”判断符,而要想进行数据的查询则使用“$search”运算符
查询指定关键字:{“$search”: “查询关键字”};
查询多个关键字(或关系):{“$search”: “查询关键字 查询关键字 …”};
查询多个关键字(与关系):{“$search”: “\”查询关键字\” \”查询关键字\” …”};
查询多个关键字(排除某一个):{“$search”: “查询关键字 查询关键字 … -排除的某个关键字”}
范例:查询单个内容
db.news.find({"$text":{"$search":"gry"}}); |
范例:包含有“gry”与“gyh”的信息
db.news.find({"$text":{"$search":"gry gyh"}}); |
范例:同时包含有“mldn”与“lxh”的内容
db.news.find({"$text":{"$search":"\"mldn\" \"lxh\""}}); |
范例:包含有“mldn”和“lxh” 没有“gyh”的信息
db.news.find({"$text":{"$search":"\"mldn\" \"lxh\" -gyh"}}); |
但是在进行全文检索操作的时候还可以使用相似度的打分来判断检索成果。
范例:为结果打分
db.news.find({"$text":{"$search":"gyh"}},{"score":{"$meta":"textScore"}}).sort({"score":{"$meta":"textScore"}}); |
按照打分的成绩进行排列,实际上就可以实现更加准确的信息搜索
但是在这里面还有一个问题,如果一个集合的字段太多了,那么每一个字段都分别设置全文检索麻烦点,所以单一些,可以为所有的字段设置全文检索
范例:为所有字段设置全文检索
db.news.ensureIndex({"$**","text"}); |
这是一种最简单的设置全文索引的方式,但是尽可能别用,因为:慢!
地理信息索引
地理信息索引分为两类:2D平面索引,另外就是2DSphere球面索引。在2D的索引里面基本上能够保存的信息就是坐标,而且坐标保存的是经纬度坐标。
范例:定义一个商铺集合
db.shop.insert({loc:[10,10]}); db.shop.insert({loc:[11,10]}); db.shop.insert({loc:[10,11]}); db.shop.insert({loc:[12,15]}); db.shop.insert({loc:[16,17]}); db.shop.insert({loc:[90,90]}); db.shop.insert({loc:[120,130]}); |
范例:为shop的集合定义2D索引
db.shop.ensureIndex({"loc":"2d"}); |
这个时候shop集合就可以实现坐标位置的查询了,有两种方式查询:
“$near”查询,查询距离某个点最近的坐标点
“$geoWithin”查询:查询某个形状内的点
范例:假设我现在的坐标是:[11,11]
db.shop.find({loc:{"$near":[11,11]}}); |
但是如果执行了以上的查询,实际上会将数据集合里面的前100个点的信息全都返回,设置距离范围。
范例:设置五个点的查询距离范围
db.shop.find({loc:{"$near":[11,11],"$maxDistance":5}}); |
在2D索引里面支持最大距离,但是不支持最小距离。
但是可以设置一个查询的范围,使用“$geoWithin”查询,而可以设置为:
矩形范围($box):{“$box”:[[x1,y1],[x2,y2]]};
圆形范围($center):{“$center”:[[x1,y1],r]};
多边型($polygon):{ “$ polygon”:[[x1,y1],[x2,y2]…]}
范例:矩形查询
db.shop.find({loc:{"$geoWithin":{"$box":[[9,9],[11,11]]}}}); |
范例:查询圆形
db.shop.find({loc:{"$geoWithin":{"$center":[[10,10],2]}}}); |
在MongoDB里面,除了一些支持的操作函数之外,还有一个重要的命令:runCommand()函数,这个函数可以执行所有特定的函数
范例:利用runCommand()实现信息查询
db.runCommand({"geoNear":"shop",near:[10,10],maxDistance:5,num:2}); |
这类命令是Mongodb是最为基础的命令。