一、Single Field Indexes
示例文档:
{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"score": 1034,
"location": { state: "NY", city: "New York" }
}
1、语法:
db.records.createIndex( { score: 1 } )
2、在嵌套字段上创建索引
db.records.createIndex( { "location.state": 1 } )
查询语法:
db.records.find( { "location.state": "CA" } )
db.records.find( { "location.city": "Albany", "location.state": "NY" } )
3、在嵌入式文档上创建索引
db.records.createIndex( { location: 1 } )
查询语法:
db.records.find( { location: { city: "New York", state: "NY" } } )
4、需要注意的点
对于以上location嵌套字段的查询,顺序与创建索引顺序不一致可以使用索引,但是查询结果记录为0,因为查询顺序不同。
示例:
> db.records.find()
{ "_id" : ObjectId("570c04a4ad233577f97dc459"), "score" : 1034, "location" : { "state" : "NY", "city" : "New York" } }
>
> db.records.find( { location: { city: "New York", state: "NY" } } ) //顺序相反,可以使用索引,但是返回0记录
>
> db.records.find( { location: { state: "NY",city: "New York" } } ) //顺序正确,返回1记录
{ "_id" : ObjectId("570c04a4ad233577f97dc459"), "score" : 1034, "location" : { "state" : "NY", "city" : "New York" } }
二、Compound Indexes
示例文档:
{
"item": "Banana",
"category": ["food", "produce", "grocery"],
"location": "4th Street Store",
"stock": 4,
"type": "cases"
}
1、语法
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
2、复合索引中包含的一些隐式索引
若我们集合中存在一个复合索引{a:1,b:1,c:1},在该索引下,相当于同时创建了如下一些索引:
{a:1,b:1,c:1}
<=> {a:1}
<=> {a:1,b:1}
<=> {a:1,b:1,c:1}
3、利用索引进行排序
示例:db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )
查询语句 | 使用索引 |
---|---|
db.data.find().sort( { a: 1 } ) | { a: 1 } |
db.data.find().sort( { a: -1 } ) | { a: 1 } |
db.data.find().sort( { a: 1, b: 1 } ) | { a: 1, b: 1 } |
db.data.find().sort( { a: -1, b: -1 } ) | { a: 1, b: 1 } |
db.data.find().sort( { a: 1, b: 1, c: 1 } ) | { a: 1, b: 1, c: 1 } |
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } ) | { a: 1, b: 1 } |
db.data.find( { a: 5 } ).sort( { b: 1, c: 1 } ) | { a: 1 , b: 1, c: 1 } |
db.data.find( { b: 3, a: 4 } ).sort( { c: 1 } ) | { a: 1, b: 1, c: 1 } |
db.data.find( { a: 5, b: { $lt: 3} } ).sort( { b: 1 } ) | { a: 1, b: 1 } |
三、Multikey indexes
1、多键索引的创建
在数组上创建索引时,MongoDB会自动为该集合创建多键索引。
2、多键索引的唯一性
由于multikey indexes会对数组中每个值做索引,所以如果该字段设置为唯一多键索引,那需要保证该集合中index数组不能重复
1)示例集合
{ "_id" : 6, "type" : "food", "item" : "bbb", "ratings" : [ 5, 9 ] }
db.cc.createIndex({ratings:1},{unique:true})
2)唯一性验证
> db.cc.insert({"_id" : 5, "type" : "food", "item" : "aaa", "ratings" : [ 1,2 ]}) //[1,2]与[5,9]不冲突
WriteResult({ "nInserted" : 1 })
>
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 7,3 ]}) //[ 7,3 ]与[1,2,5,9]不冲突
WriteResult({ "nInserted" : 1 })
>
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 7,4 ]}) //7与[1,2,3,5,7,9]冲突
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.cc index: ratings_1 dup key: { : 7.0 }"
}
})
> db.cc.insert({"type" : "food", "item" : "aaa", "ratings" : [ 6,9 ]}) //9与[1,2,3,5,7,9]冲突
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.cc index: ratings_1 dup key: { : 9.0 }"
}
})
>
> db.cc.find()
{ "_id" : 6, "type" : "food", "item" : "bbb", "ratings" : [ 5, 9 ] }
{ "_id" : 5, "type" : "food", "item" : "aaa", "ratings" : [ 1, 2 ] }
{ "_id" : ObjectId("5d2e7c6dc5002cd792e912a9"), "type" : "food", "item" : "aaa", "ratings" : [ 7, 3 ] }
2、多键索引的一些限制
1)不能同时在两个数组字段建立复合multikey indexes
2)由于MongoDB3.6版本对排序行为上做了一些改变,导致现在对multikey index进行排序时,查询计划包括一个阻塞排序的阶段,从而对性能产生影响。在排序阻塞阶段,必须等待所有输入完成才能进行排序然后输出结果;对于一个非阻塞排序或者索引排序,sort操作只需要扫描index产生一个有序的请求。
3)多键索引不能做分片键,但是,如果一个分片是复合索引的前缀,这个复合索引支持多键索引。
4)hash索引不支持多键索引
5)多键索引不支持覆盖索引查询
6)多键索引无法使用$expr
3、多键索引是如何利用索引进行查询?
db.inventory.find( { ratings: [ 5, 9 ] } ),对于该multikey index的查询,MongoDB通过索引查找出所有包含5的记录,然后过滤出[5,9]的记录
4、Multikey Index Bounds
db.survey.insertMany([
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] },
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }])db.survey.createIndex( { ratings: 1 } )
1)Intersect Bounds
db.survey.find( { ratings : { $elemMatch: { $gte: 3, $lte: 6 } } } )
<=> ratings: [ [ 3, 6 ] ]
执行计划:
"indexBounds" : {
"ratings" : [
"[3.0, 6.0]"
]
}
2)不使用 $elemMatch的情况下MongoDB不会使用multikey inedex的交集
db.survey.find( { ratings : { $gte: 3, $lte: 6 } } )
<=> ratings: [ [ 3, Infinity ] ] or [ [ -Infinity, 6 ] ]
执行计划:
"indexBounds" : {
"ratings" : [
"[-inf.0, 6.0]"
]
}
3)Compound Bounds - 等值查询
db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )
db.survey.createIndex( { item: 1, ratings: 1 } )
<=> ratings: { item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }
执行计划:
"indexBounds" : {
"item" : [
"[\"XYZ\", \"XYZ\"]"
],
"ratings" : [
"[3.0, inf.0]"
]
}
4)Compound Bounds - 范围查询
db.survey.find( {item: { $gte: "L", $lte: "Z"}, ratings : { $elemMatch: { $gte: 3, $lte: 6 } }} )
<=> ratings: "item" : [ [ "L", "Z" ] ], "ratings" : [ [3.0, 6.0] ]
执行计划:
"indexBounds" : {
"item" : [
"[\"L\", \"Z\"]"
],
"ratings" : [
"[3.0, 6.0]"
]
}
5)Compound Bounds
1.示例集合
> db.survey.insertMany([{ _id: 1, item: { name: "ABC", manufactured: 2016 }, ratings: [ 2, 9 ] },
{ _id: 2, item: { name: "XYZ", manufactured: 2013 }, ratings: [ 4, 3 ] }])
>
> db.survey.createIndex( { "item.name": 1, "item.manufactured": 1, ratings: 1 } )
2.查询结果
> db.survey.find( { "item.name": "L" , "item.manufactured": 2012 } )
<=> "item.name" : [ ["L", "L"] ], "item.manufactured" : [ [2012.0, 2012.0] ]
执行计划:
"indexBounds" : {
"item.name" : [
"[\"L\", \"L\"]"
],
"item.manufactured" : [
"[2012.0, 2012.0]"
],
"ratings" : [
"[MinKey, MaxKey]"
]
}
四、Text Indexes
示例集合
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9904"), "song" : "1. Hotel California", "lyrics" : "On a dark desert highway, cool wind in my hair. Warm smell of colitas, rising up through the air." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9905"), "song" : "2. Hotel California", "lyrics" : "Up ahead in the distance, I saw a shimmering light. My head grew heavy and my sight grew dim." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9906"), "song" : "3. Hotel California", "lyrics" : "Such a lovely place, Such a lovely face." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9907"), "song" : "4. Hotel California", "lyrics" : "Some dance to remember, some dance to forget." }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9908"), "song" : "5. Hotel California", "lyrics" : "Welcome to the Hotel California" }
{ "_id" : ObjectId("5d2f35f6c1aace30b3ce9909"), "song" : "hell world", "lyrics" : "Welcome to beijing" }
1、语法
一个集合只能有一个text索引,但是该text可以是多个字段的复合索引
db.quotes.createIndex({ content : "text" })
db.reviews.createIndex({subject: "text",comments: "text"})
2、权重
1)创建全文索引默认权重为1
2)各字段的权重分布会影响到查询时的优先策略
db.blob.insertMany([{_id: 1,content: "This morning I had a cup of coffee.",about: "beverage",keywords: ["coffee"]},
{_id: 2,content: "Who doesn't like cake?",about: "food",keywords: [ "cake", "food", "dessert" ]}])
db.blog.createIndex(
{
content: "text",
keywords: "text",
about: "text"
},
{
weights: { //执行权重
content: 10,
keywords: 5
},
name: "TextIndex" //指定索引名字
}
)
3、通配符文本索引 - 表示在所有字段创建一个全文索引
db.ttlsa_com.ensureIndex({"$**": "text"})
4、复合全文索引
{ "_id" : 1, "dept" : "tech", "description" : "lime green computer" }
{ "_id" : 2, "dept" : "tech", "description" : "wireless red mouse" }
{ "_id" : 3, "dept" : "kitchen", "description" : "green placemat" }
{ "_id" : 4, "dept" : "kitchen", "description" : "red peeler" }
{ "_id" : 5, "dept" : "food", "description" : "green apple" }
{ "_id" : 6, "dept" : "food", "description" : "red potato" }db.inventory.createIndex({dept: 1,description: "text"})
> db.inventory.find( { dept: "kitchen", $text: { $search: "green" } } )
{ "_id" : 3, "dept" : "kitchen", "description" : "green placemat" }
5、查询语法
db..find({
$text:
{
$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean>
}
})
五、2dsphere Indexes
1、2dsphere索引支持对于球体的地理位置计算
2、2dsphere索引默认为稀疏索引
如果某一文档缺少2dsphere字段(null或为空),那么该文档不会创建索引。对于一个包含其它类型的复合2dsphere索引,该文档索引的使用仅仅与2dsphere字段有关。
示例集合:
{ "_id" : ObjectId("5d2fd9a67737353186206a70"), "loc" : { "type" : "Point", "coordinates" : [ -73.97, 40.77 ] }, "name" : "Central Park", "category" : "Parks" }
{ "_id" : ObjectId("5d2fd9a67737353186206a71"), "loc" : { "type" : "Point", "coordinates" : [ -73.88, 40.78 ] }, "name" : "La Guardia Airport", "category" : "Airport" }db.places.createIndex( { category : 1 , loc : "2dsphere" } )
> db.places.find({category:"Airport"}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.places",
"indexFilterSet" : false,
"parsedQuery" : {
"category" : {
"$eq" : "Airport"
}
},
"winningPlan" : {
"stage" : "COLLSCAN", //全文档扫描
"filter" : {
"category" : {
"$eq" : "Airport"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "dbslave2",
"port" : 28002,
"version" : "4.0.10-5",
"gitVersion" : "7dab0a3a7b7b40cf71724b5a11eff871f8c3885c"
},
"ok" : 1
}
3、2dsphere一些特性
1)version 2 之后,2dsphere索引支持GeoJSON格式对象写入
2)2dsphere索引没有办法作为分片键
3)2dsphere索引字段必须是坐标或者 GeoJSON 类型,否则会报错
4)2dsphere 支持 Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon、Geometry Collection的查询
4、创建2dsphere索引语法:
1)2dsphere索引
db.places.createIndex( { loc : "2dsphere" } )
2)复合2dsphere索引
与2d索引不同,2dsphere索引不需要将location字段放在最左前缀。
db.places.createIndex( { category : 1 , loc : "2dsphere" } )
db.places.createIndex( { loc : "2dsphere" , category : -1, name: 1 } )
5、查询语法
Polygon相关查询
1)查询指定地址位置内所有的点
语法:
db.<collection>.find( { <location field> :
{ $geoWithin :
{ $geometry :
{ type : "Polygon" ,
coordinates : [ <coordinates> ]
} } } } )
示例:查询由coordinates指定的多边形内所有的点和形状
db.places.find( { loc :
{ $geoWithin :
{ $geometry :
{ type : "Polygon" ,
coordinates : [ [
[ 0 , 0 ] ,
[ 3 , 6 ] ,
[ 6 , 1 ] ,
[ 0 , 0 ]
] ]
} } } } )
2)交集
1.语法
db.<collection>.find( { <location field> :
{ $geoIntersects :
{ $geometry :
{ type : "<GeoJSON object type>" ,
coordinates : [ <coordinates> ]
} } } } )
2.示例:查找与coordinates点组成多边形所有相交的点和形状
db.places.find( { loc :
{ $geoIntersects :
{ $geometry :
{ type : "Polygon" ,
coordinates: [ [
[ 0 , 0 ] ,
[ 3 , 6 ] ,
[ 6 , 1 ] ,
[ 0 , 0 ]
] ]
} } } } )
Point的点相关查询
3)临近GeoJSON Point的点
语法:
db.<collection>.find( { <location field> :
{ $near :
{ $geometry :
{ type : "Point" ,
coordinates : [ <longitude> , <latitude> ] } ,
$maxDistance : <distance in meters>
} } } )
示例:
db.places.find( { loc :
{ $near :
{ $geometry :
{ type : "Point" ,
coordinates : [ -88 , 30 ] } ,
$maxDistance : 3963
} } } )
4)指定point以及半径内所有的点
语法:
db.<collection>.find( { <location field> :
{ $geoWithin :
{ $centerSphere :
[ [ <x>, <y> ] , <radius> ] }
} } )
示例:
db.places.find( { loc :
{ $geoWithin :
{ $centerSphere :
[ [ -88 , 30 ] , 10 / 3963.2 ]
} } } )
六、2d Indexes
1、2d索引的一些特性
1)在MongoDB 2.2版本之前或者地址位置字段没有使用GeoJSON进行存储的情况下,我们使用2d索引比较多。
2)2d索引一般是用来计算平面上的计算,对于球面的一些几何计算,或者以GeoJSON形式来进行存储的字段,需要使用2dsphere索引
3)2d索引本质上也是一个稀疏索引
4)2d索引不支持collation选项
5)对于2d复合索引来讲,必须将2d索引字段放在复合索引最前缀
> db.places.createIndex( { state:1,"locs": "2d"} )
{
"ok" : 0,
"errmsg" : "2d has to be first in index",
"code" : 16801,
"codeName" : "Location16801"
}
2、创建语法
db.<collection>.createIndex( { <location field> : "2d" ,
<additional field> : <value> } ,
{ <index-specification options> } )db.collection.createIndex( { <location field> : "2d" } ,
{ min : <lower bound> , max : <upper bound> } ) //设置最大最小边界值和精度。默认情况下,最大值和最小值的范围是[ -180 , 180 ),精度是26位的精度
3、查询语法
1)查询在指定范围内所有的点 - 平面
语法:
db.<collection>.find( { <location field> :
{ $geoWithin :
{ $box|$polygon|$center : <coordinates>
} } } )
示例:
查询在[ 0 , 0 ],[ 100 , 100 ]之内的所有点:
db.places.find( { loc :
{ $geoWithin :
{ $box : [ [ 0 , 0 ] ,
[ 100 , 100 ] ]
} } } )
查询以[-74, 40.74 ]为中心,10为半径的范围内所有的点:
db.places.find( { loc: { $geoWithin :
{ $center : [ [-74, 40.74 ] , 10 ]
} } } )
2)查询球面中的范围查询
语法:
db.<collection>.find( { <location field> :
{ $geoWithin :
{ $centerSphere : [ [ <x>, <y> ] , <radius> ] }
} } )
示例:
db.<collection>.find( { loc : { $geoWithin :
{ $centerSphere :
[ [ 88 , 30 ] , 10 / 3963.2 ]
} } } )
3)查询一个平面的临近点
语法:
db.<collection>.find( { <location field> :
{ $near : [ <x> , <y> ] }
} )
示例:
db.place.find( { loc :{ $near : [ 23 , 57 ]} } )
4)精确匹配一个点
语法:
db.<collection>.find( { loc: [ <x> , <y> ] } )
示例:
db.place.find( { loc : [ 23 , 57 ] } )
七、Hash Indexes
1、hash索引的一些特点
1)hash索引可以做分片键,这会使数据分布更加随机性
2)hash索引会通过一个hash函数来计算该文档的hash索引值,hash支持嵌套文档,但是不支持多键。
3)hash索引是由MongoDB实例来自动计算使用hash索引的,应用程序无需对其进行hash计算
2、创建hash索引语法
db.collection.createIndex( { _id: "hashed" } )
3、hash索引使用的一些限制
1)hash索引不支持创建复合索引
2)hash索引仅支持等值查询,也可以在相同的字段创建普通索引,范围查询会优先使用普通索引,等值查询优先使用hash索引。