第五章 索引
>db.users.find({"username":"retacn yue"})
{ "_id" : ObjectId("586b40507dfc144b68de4071"),"relationships" : { "enemies" : 2, "friend" : 32}, "username" : "retacn yue", "age" : 33,"sex" : "ma
le", "location" :"ZiBo", "emails" : [ "zhenhuayue@hotmail.com","zhenhuayue@163.com", "zhenhuayue@soho.com", "zhenhuayue@126.com"], "state" : null,
"languages" : [ "java","python", "c", "c++" ] }
>db.users.ensureIndex({"username":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
>
扩展索引
创建索引需要考虑以下问题
1 作什么查询,哪些键要索引
2 索引方向
3 扩展中键的排列
索引内嵌文档中的键
> db.blog.posts.findOne()
{
"_id" : ObjectId("586f21115da1e3bac2c373fe"),
"title" : "A blog post",
"content" : "...",
"author" : {
"name" : "retacnyue",
"email" :"zhenhuayue@sina.com"
},
"comments" : [
{
"name" :"yue",
"email" :"zhenhuayue@126.com",
"content" :"good",
"votes" : 11
},
{
"name" :"three",
"email" :"zhenhuayue@hotmail.com",
"content" :"better",
"votes" : 8
},
{
"name" :"zhenhua",
"email" :"zhenhuayue@qq.com",
"content" :"best",
"votes" : 11
}
]
}
> db.users.ensureIndex({"author.name":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
>
为排序创建索引
无索引的排序,当集合大到不能在内存中排序,mongodb就会报错
索引名称
索引名形式:
Keyname1_dir1_keyname2_dir2_...keynameN_dirN
自定义索引名称
>db.users.ensureIndex({"location":1},{"location":"seq_location"})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 3,
"numIndexesAfter" : 4,
"ok" : 1
}
二唯一索引
确保文档中的username键都有一个唯一值,可以创建唯一索引
>db.users.ensureIndex({"age":1},{"unique":true})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 4,
"numIndexesAfter" : 5,
"ok" : 1
}
修改索引
#删除指定键的索引
> db.runCommand({"dropIndexes":"users","index":"username_1"})
{ "nIndexesWas" : 5,"ok" : 1 }
>db.runCommand({"dropIndexes":"users","index":"location_1"})
{ "nIndexesWas" : 4,"ok" : 1 }
#删除所有索引
>db.runCommand({"dropIndexes":"users","index":"*"})
{
"nIndexesWas" : 3,
"msg" : "non-_id indexes dropped for collection",
"ok" : 1
}
>
消除重复
如果在创建索引前,数据库中已经有重复的键值,如果想要将重复的文档值全部删除,可以作如下操作
#添加用户名重复的键值
>db.users.insert({"username":"retacn yue"})
WriteResult({ "nInserted" : 1 })
#查询所有记录
> db.users.find()
{ "_id" :ObjectId("586b40507dfc144b68de4071"), "relationships" : {"enemies" : 2, "friend" : 32 }, "username" :"retacn yue", "age" : 33, "sex" : "ma
le", "location" :"ZiBo", "emails" : [ "zhenhuayue@hotmail.com","zhenhuayue@163.com", "zhenhuayue@soho.com","zhenhuayue@126.com" ], "state" : null,
"languages" : [ "java","python", "c", "c++" ] }
{ "_id" :ObjectId("58708a439193775a5f6b5f14"), "username" :"ann", "age" : 30, "sex" : "female","location" : "BoShan", "relationships" : {"enemies"
: 1,"friend" : 20 }, "emails" : [ "znn@163.com","ann@sina.com" ], "state" : "T","languages" : [ "java", "python", "c++"] }
{ "_id" :ObjectId("58708aeb9193775a5f6b5f16"), "username" :"mike", "age" : 15, "sex" : "male","location" : "HuanTai", "relationships" : {"enemies"
: 3,"friend" : 18 }, "emails" : [ "mike@163.com","mike@sina.com" ], "state" : "F","languages" : [ "java", "c++" ] }
{ "_id" :ObjectId("58708e5e9193775a5f6b5f18"), "username" :"andy", "age" : 18, "sex" : "female","location" : "ZhangDian", "relationships" : {"enem
ies" : 2, "friend" : 15 },"emails" : [ "andy@163.com", "andy@sina.com" ],"state" : "T", "languages" : [ "java","c", "c++" ] }
{ "_id" :ObjectId("5871d6cbc1be409ee45a7899"), "username" :"retacn yue" }
#这时创建唯一索引失败
>db.users.ensureIndex({"username":1},{"unique":true})
{
"ok" : 0,
"errmsg" : "E11000 duplicate key error collection:test.users index: username_1 dup key: { : \"retacn yue\" }",
"code" : 11000
}
>
#如果想保留第一个文档,删除后面的重得文档,可以作如下操作
在mongodb在3.0后不建议使用
>db.users.ensureIndex({"username":1},{"unique":true,"dropDups":true})
复合唯一索引,单个健的值可以相同,只要键的组合不同就好
使用explain和hint
#会返回查询所使用的索引情况
#在建立索引前
>db.users.find({"username":"retacn yue"}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" :"test.users",
"indexFilterSet" :false,
"parsedQuery" : {
"username" :{
"$eq": "retacn yue"
}
},
"winningPlan" : {
"stage" :"COLLSCAN",
"filter" : {
"username" : {
"$eq" : "retacn yue"
}
},
"direction" :"forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" :"retacn",
"port" : 27017,
"version" :"3.2.11",
"gitVersion" :"009580ad490190ba33d1c6253ebd8d91808923e4"
},
"ok" : 1
}
#在建立索引后
>db.users.find({"username":"retacn yue"}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" :"test.users",
"indexFilterSet" :false,
"parsedQuery" : {
"username" :{
"$eq": "retacn yue"
}
},
"winningPlan" : {
"stage" :"FETCH",
"inputStage": {
"stage" : "IXSCAN",
"keyPattern": {
"username" : 1
},
"indexName" : "username_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds": {
"username" : [
"[\"retacn yue\", \"retacn yue\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" :"retacn",
"port" : 27017,
"version" :"3.2.11",
"gitVersion" :"009580ad490190ba33d1c6253ebd8d91808923e4"
},
"ok" : 1
}
四索引的管理
索引的元信息保存在system.indexes集合中,不能进行插入和删除文档的操作
可以使用ensureIndex和dropIndex进行
修改索引
#创建索引的工作在后台完成
>db.users.ensureIndex({"username":1},{"background":true})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
查看索引,删除索引
#查看当前数据库中建立的索引
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" :"_id_",
"ns" :"test.users"
},
{
"v" : 1,
"key" : {
"username" :1
},
"name" :"username_1",
"ns" :"test.users",
"background" : true
}
]
五地理空间索引
比如果查找离当前位置最近的n个场所,mongodb创建了专门的索引,地理空间索引
db.map.ensureIndex({“gps”:”2d”})
Gps的键值必须是一对值
{“gps”:{1,100}}
{“gps”:{“x”:20,”y”:30}}
也可以指定最大值,最小值
db.map.ensureIndex({“gps”:”2d”},{“min”:-100,”max”:100})
查询时可以使用$near
Db.map.find({“gps”:{“$near”:[10,20]}}).limit(10)
也可以使用geoNear来完成同上操作
db.runCommand({geoNear:”map”,near:[10,20],num:10})
也可以找到指定形状内的文档,box第一个元素指定了左下角的坐标,第二个元素指定右上角的坐标
Db.map.find({“gps”:{“$within”:{“$box”:[[10,20][15,30]]}}})
也可以用来查询圆内的所有点
Db.map.find({“gps”:{“$within’:{“$center”:[12,25],5}}})
复合地理空间索引
例如查询附近的咖啡店,可以将地理空间索引与普通索引组合起来
#创建索引
db.map.ensureIndex({“location”:”2d”,”desc”:1})
#查询
Db.map.find({“location”:{“$near”:[70,30]},”desc”:”coffeeshop”}).limit(1)