常见的查询索引
_id索引
_id 索引是绝大多数集合默认建立的索引。对于每一个插入的数据。MongoDB 会自己主动生成一条唯一的 _id 字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | > db.jerome_2.collection.insert({x:2}) WriteResult({ "nInserted" : 1 }) > db.jerome_2.collection.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_" , "ns" : "jerome.jerome_2.collection" } ] > db.jerome_2.collection.findOne() { "_id" : ObjectId( "557004f1f2824fa15224e20b" ), "x" : 2 } > |
单键索引
单键索引是最普通的索引,与_id 索引不同。单键索引不会自己主动创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | > db.jerome_2.collection.ensureIndex({x:1}) # 创建单键索引 { "createdCollectionAutomatically" : false , "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.jerome_2.collection.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_" , "ns" : "jerome.jerome_2.collection" }, { "v" : 1, "key" : { "x" : 1 }, "name" : "x_1" , "ns" : "jerome.jerome_2.collection" } ] > db.jerome_2.collection. find ({x:1}) #使用创建的索引查询 { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } > |
多键索引
多键索引和单键索引创建形式同样,差别在于字段的值。
单键索引:值为一个单一的值,比如字符串,数字或者日期。
多键索引:值具有多个记录,比如数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | > db.jerome_2.collection.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_" , "ns" : "jerome.jerome_2.collection" }, { "v" : 1, "key" : { "x" : 1 }, "name" : "x_1" , "ns" : "jerome.jerome_2.collection" } ] > db.jerome_2.collection. find () { "_id" : ObjectId( "557004f1f2824fa15224e20b" ), "x" : 2 } { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } > db.jeroem_2.collection.insert({x:[1,2,3,4,5]}) #插入一条数组数据,对于这条数据来讲。mongodb为其创建了一个多键索引 WriteResult({ "nInserted" : 1 }) |
复合索引
当我们的查询条件不仅仅有一个时。就须要建立复合索引。
1 2 3 4 5 6 7 8 9 10 | > db.jerome_2.collection.ensureIndex({x:1,y:1}) #创建 { "createdCollectionAutomatically" : false , "numIndexesBefore" : 2, "numIndexesAfter" : 3, "ok" : 1 } > db.jerome_2.collection. find ({x:1,y:2}) #使用 { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } > |
过期索引
过期索引是在一段时间后会过期的索引。在索引过期后,对应的数据会被删除。这适合存储一些在一段时间之后会失效的数据。比方用户的登陆信息、存储的日志等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > db.jerome_2.collection.ensureIndex({ time :1},{expireAfterSeconds:30}) #创建过期索引,过期时间30秒 { "createdCollectionAutomatically" : false , "numIndexesBefore" : 3, "numIndexesAfter" : 4, "ok" : 1 } > db.jerome_2.collection.insert({ time :new Date()}) #插入数据測试 WriteResult({ "nInserted" : 1 }) > db.jerome_2.collection. find () { "_id" : ObjectId( "557004f1f2824fa15224e20b" ), "x" : 2 } { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } { "_id" : ObjectId( "55700b17f2824fa15224e20e" ), "time" : ISODate( "2015-06-04T08:23:51.531Z" ) } > db.jerome_2.collection. find () { "_id" : ObjectId( "557004f1f2824fa15224e20b" ), "x" : 2 } { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } { "_id" : ObjectId( "55700b17f2824fa15224e20e" ), "time" : ISODate( "2015-06-04T08:23:51.531Z" ) } > db.jerome_2.collection. find () #时间过了就找不到了 { "_id" : ObjectId( "557004f1f2824fa15224e20b" ), "x" : 2 } { "_id" : ObjectId( "557005a5f2824fa15224e20c" ), "x" : 1, "y" : 2, "z" : 3 } > |
使用限制
1. 存储在过期索引字段的值必须是指定的时间类型。
(必须是ISODate或者ISODate数组,不能使用时间戳。否则不能被自己主动删除)
2. 假设指定了ISODate数组。则依照最小的时间进行删除。
3. 过期索引不能是复合索引。
4. 删除时间不是精确的。(删除过程是由后台程序没60s跑一次,并且删除也须要一些时间,所以存在误差)
全文索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | > db.jerome_2.ensureIndex({ "article" : "text" }) #创建全文可搜索索引 { "createdCollectionAutomatically" : true , "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.jerome_2.insert({ "article" : "aa bb cc dd ee" }) #插入測试数据 WriteResult({ "nInserted" : 1 }) > db.jerome_2.insert({ "article" : "aa bb rr gg zz" }) WriteResult({ "nInserted" : 1 }) > db.jerome_2.insert({ "article" : "aa bb" }) WriteResult({ "nInserted" : 1 }) > db.jerome_2.insert({ "article" : "aa bb cc zz ff ww" }) WriteResult({ "nInserted" : 1 }) > db.jerome_2. find ({$text:{$search: "aa" }}) #查找 { "_id" : ObjectId( "5572904271c0bbd90f4ce0e2" ), "article" : "aa bb rr gg zz" } { "_id" : ObjectId( "5572903371c0bbd90f4ce0e1" ), "article" : "aa bb cc dd ee" } { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" } { "_id" : ObjectId( "5572904771c0bbd90f4ce0e3" ), "article" : "aa bb" } > db.jerome_2. find ({$text:{$search: "ff" }}) { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" } > db.jerome_2. find ({$text:{$search: "aa bb cc" }}) #空格表示或 { "_id" : ObjectId( "5572904271c0bbd90f4ce0e2" ), "article" : "aa bb rr gg zz" } { "_id" : ObjectId( "5572903371c0bbd90f4ce0e1" ), "article" : "aa bb cc dd ee" } { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" } { "_id" : ObjectId( "5572904771c0bbd90f4ce0e3" ), "article" : "aa bb" } > db.jerome_2. find ({$text:{$search: "aa bb -cc" }}) #-cc 表示不包括cc { "_id" : ObjectId( "5572904271c0bbd90f4ce0e2" ), "article" : "aa bb rr gg zz" } { "_id" : ObjectId( "5572904771c0bbd90f4ce0e3" ), "article" : "aa bb" } > db.jerome_2. find ({$text:{$search: ""aa" "bb" "cc"" }}) #加引號,表示与 { "_id" : ObjectId( "5572903371c0bbd90f4ce0e1" ), "article" : "aa bb cc dd ee" } { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" } > |
全文索引类似度
$meta操作符:{score:{$meta:"textScore"}},返回结果的类似度,与 sort 一起使用能够达到非常好的有用效果。
1 2 3 4 5 6 7 8 9 10 11 | > db.jerome_2. find ({$text:{$search: "aa bb" }},{score:{$meta: "textScore" }}) #score越高,类似度越高。 { "_id" : ObjectId( "5572904271c0bbd90f4ce0e2" ), "article" : "aa bb rr gg zz" , "score" : 1.2 } { "_id" : ObjectId( "5572903371c0bbd90f4ce0e1" ), "article" : "aa bb cc dd ee" , "score" : 1.2 } { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" , "score" : 1.1666666666666667 } { "_id" : ObjectId( "5572904771c0bbd90f4ce0e3" ), "article" : "aa bb" , "score" : 1.5 } > db.jerome_2. find ({$text:{$search: "aa bb" }},{score:{$meta: "textScore" }}). sort ({score:{$meta: "textScore" }}) #依据score进行排序 { "_id" : ObjectId( "5572904771c0bbd90f4ce0e3" ), "article" : "aa bb" , "score" : 1.5 } { "_id" : ObjectId( "5572903371c0bbd90f4ce0e1" ), "article" : "aa bb cc dd ee" , "score" : 1.2 } { "_id" : ObjectId( "5572904271c0bbd90f4ce0e2" ), "article" : "aa bb rr gg zz" , "score" : 1.2 } { "_id" : ObjectId( "5572905671c0bbd90f4ce0e4" ), "article" : "aa bb cc zz ff ww" , "score" : 1.1666666666666667 } > |
使用限制
1. 每次查询仅仅能指定一个$text查询
2. $text查询不能出如今$nor查询中
3. 查询中假设包括了$text。hint不再起作用
4. MongoDB 索引如今还不支持中文
地理位置索引
概念:
将一些点的位置存储在 MongoDB 中。创建索引后,能够依照位置来查找其它点。
分类:
1. 2d 索引。用于存储和查找平面上的点。
2. 2dsphere 索引,用于存储和查找球面上的点。
查找方式:
1. 查找距离某个点一定距离内的点。
2. 查找包括在某区域内的点。
2d索引
1. $near查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | > db.location.ensureIndex({ "w" : "2d" }) #创建2d索引 > db.location.insert({w:[1,1]}) #插入測试数据。经纬度[经度,纬度]。 WriteResult({ "nInserted" : 1 }) > db.location.insert({w:[1,2]}) WriteResult({ "nInserted" : 1 }) > db.location.insert({w:[2,3]}) WriteResult({ "nInserted" : 1 }) > db.location.insert({w:[100,80]}) WriteResult({ "nInserted" : 1 }) > db.location. find ({w:{$near:[1,1]}}) #查询距离某个点近期的点 { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a97aaba41684d6e8826f" ), "w" : [ 100, 80 ] } > db.location. find ({w:{$near:[1,1],$maxDistance:2}}) #能够使用maxDistance限制(near不能使用minDistance) { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } |
2. $geoWithin查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | > db.location. find ({w:{$geoWithin:{$box:[[0,0],[3,3]]}}}) #矩形 { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } > db.location. find ({w:{$geoWithin:{$box:[[1,2],[2,3]]}}}) { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } > db.location. find ({w:{$geoWithin:{$center:[[0,0],100]}}}) #圆形。100是半径 { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } > db.location. find ({w:{$geoWithin:{$center:[[0,0],1000]}}}) { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a97aaba41684d6e8826f" ), "w" : [ 100, 80 ] } { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } > db.location. find ({w:{$geoWithin:{$polygon:[[0,0],[0,1],[2,5],[6,1]]}}}) #多边形查询(各个点围成的多边形的范围) { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } > db.location. find ({w:{$geoWithin:{$polygon:[[0,0],[0,1],[2,5],[6,1000],[1001,0]]}}}) { "_id" : ObjectId( "5572a970aba41684d6e8826e" ), "w" : [ 2, 3 ] } { "_id" : ObjectId( "5572a97aaba41684d6e8826f" ), "w" : [ 100, 80 ] } { "_id" : ObjectId( "5572a961aba41684d6e8826c" ), "w" : [ 1, 1 ] } { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } |
3. 使用geoNear查询
geoNear使用runCommand命令进行使用
db.runCommand(
{getNear:<collection>,
near:[x,y],
minDistance:(对2d索引无效)
maxDistance:
num:
}
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | > db.runCommand({geoNear: "location" ,near:[1,2],maxDistance:10,num:1}) { "results" : [ { "dis" : 0, "obj" : { "_id" : ObjectId( "5572a965aba41684d6e8826d" ), "w" : [ 1, 2 ] } } ], "stats" : { "nscanned" : NumberLong(1), "objectsLoaded" : NumberLong(1), "avgDistance" : 0, "maxDistance" : 0, "time" : 2 }, "ok" : 1 } > |
2dsphere 球面地理位置索引
概念:球面地理位置索引。
创建方式:db.collection.ensureIndex({w:"2dsphere"})
位置表示方式:
GeoJson:描写叙述一个点。一条直线,多边形等形状
格式:{type:"",coordinates:[<coordinates>]}
支持$minDistance与$maxDistance
创建索引比較重要属性介绍
格式
db.collection.ensureIndex({param},{param}) #第二个參数是索引的属性
比較重要的属性有:名字、唯一性、稀疏性、是否定时删除。
1. 名字,name指定:db.collection.ensureIndex({},{name:""})
默认命名格式是例如以下这种
单键索引。1和-1,命名是依据key+_1/-1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | > db.jerome_2.ensureIndex({x:1}) > db.jerome_2.ensureIndex({y:-1}) > db.jerome_2.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_" , "ns" : "jerome.jerome_2" }, { "v" : 1, "key" : { "x" : 1 }, "name" : "x_1" , "ns" : "jerome.jerome_2" }, { "v" : 1, "key" : { "y" : -1 }, "name" : "y_-1" , "ns" : "jerome.jerome_2" } |
复合索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | > db.jerome_2.ensureIndex({x:1,y:-1}) > db.jerome_2.ensureIndex({x:1,y:-1,z:1}) > db.jerome_2.getIndexes() [ { "v" : 1, "key" : { "x" : 1, "y" : -1 }, "name" : "x_1_y_-1" , "ns" : "jerome.jerome_2" }, { "v" : 1, "key" : { "x" : 1, "y" : -1, "z" : 1 }, "name" : "x_1_y_-1_z_1" , "ns" : "jerome.jerome_2" } ] |
MongoDB 对索引限制是125字节,所以我们须要自己定义索引名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | > db.jerome_2.ensureIndex({x:1,y:1,z:1,m:1},{name: "normal_index" }) > db.jerome_2.getIndexes() [ { "v" : 1, "key" : { "x" : 1, "y" : 1, "z" : 1, "m" : 1 }, "name" : "normal_index" , "ns" : "jerome.jerome_2" } ] > db.jerome_2.dropIndex( "normal_index" ) { "nIndexesWas" : 7, "ok" : 1 } > |
2. 唯一性。unique 指定:db.collection.ensureIndex({},{unique:true/false})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | > db.jerome.ensureIndex({m:1,n:1},{unique: true }) { "createdCollectionAutomatically" : true , "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.jerome.insert({m:1,n:2}) WriteResult({ "nInserted" : 1 }) > db.jerome.insert({m:1,n:2}) WriteResult({ "nInserted" : 0, "writeError" : { "code" : 11000, "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: jerome.jerome.$m_1_n_1 dup key: { : 1.0, : 2.0 }" } }) > |
3. 稀疏性,sparse 指定:db.collection.ensureIndex({},{sparse:true/false})
默认创建的索引是不稀疏的。
由于 MongoDB 没有固定的格式,插入的时候可能插入不存在的字段。比方x:1,MongoDB 会为这条不存在的字段创建索引。假设不希望发现这种事情能够指定稀疏索引为 true,就不会为不存在的字段创建索引了。
能够降低磁盘占用和增大插入速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | > db.jerome.insert({ "m" :1}) WriteResult({ "nInserted" : 1 }) > db.jerome.insert({ "n" :1}) WriteResult({ "nInserted" : 1 }) > db.jerome. find ({m:{$exists: true }}) #exists查找数据集合中一个字段存在或者不存在的记录 { "_id" : ObjectId( "55729ec1aba41684d6e8826a" ), "m" : 1 } { "_id" : ObjectId( "55729d5caba41684d6e88268" ), "m" : 1, "n" : 2 } > db.jerome.ensureIndex({m:1},{sparse: true }) #创建稀疏索引 { "createdCollectionAutomatically" : false , "numIndexesBefore" : 2, "numIndexesAfter" : 3, "ok" : 1 } > db.jerome. find ({m:{$exists: false }}) #MongoDB内部问题。所以找得到,通过以下强制指定索引 { "_id" : ObjectId( "55729ec7aba41684d6e8826b" ), "n" : 1 } > db.jerome. find ({m:{$exists: false }}).hint( "m_1" ) #以下这条记录。不存在m字段,所以不会创建索引。所以查不到记录 > |
注意:不能在稀疏索引上查找这个字段不存在的记录。
4. 是否定时删除
过期索引,前面已介绍。
參考
1. 慕课网