MongoDB 之滴滴、摩拜都在用的索引

(MapReduce的在后面)

第一关:了解并创建一个简单索引

索引的原理:

对某个键按照升续或降续创建索引,查询时首先根据查询条件查找到对应的索引条目,然后找到索引条目对应的文档指针(文档在磁盘上的存储位置),根据文档指针再去磁盘中找到相应的文档,整个过程不需要扫描全表,速度比较快

每个文档被插入集合时,如果没有给它指定索引_id,MongoDB 会自动给它创建一个默认索引_id,是个 ObjectId 对象

索引基本操作

1、创建索引(单字段索引)

db.person.createIndex({key:1})
  1. key :要创建索引的键;
  2. 如果为 1, 按照升序创建索引,而如果为 -1,则是按降序创建索引

 

2、查询索引

(1).查询集合索引:

db.person.getIndexes()

 

(2)查询全部索引

db.system.indexes.find()

3、删除索引

(1)通过指定索引名称删除该索引:

db.person.dropIndex("ageIdx")

(2).通过指定集合删除集合中的全部索引:

db.person.dropIndexes()

 

编程测试代码:

document=([

{_id:1,name: "王小明",age:15,score:90},

{_id:2,name: "周晓晓",age:18,score:86},

{_id:3,name: "王敏",age:20,score:96},

{_id:4,name: "李小亮",age:15,score:74},

{_id:5,name: "张青青",age:21,score:88}

])

db.student.insert(document)

db.student.createIndex({score:-1})

第二关:常见索引的创建

创建常见索引:

创建索引的基本语法: db.集合.createIndex({属性1: 1/-1, 属性2: 1/-1})

1、创建复合索引

和创建单字段索引的方法差不多,只是选取了多个键一同作为索引,中间以逗号隔开:

db.person.createIndex({age: 1, name: 1})

 

2、创建多 key 索引

当索引的字段为数组时,创建出的索引称为多 key 索引,多 key 索引会为数组的每个元素建立一条索引,比如 person 集合加入一个 habbit 字段(数组)用于描述兴趣爱好:

{name : '王小明', age : 19, habbit: ['football', 'runnning']}

需要查询有相同兴趣爱好的人就可以利用 habbit 字段的多 key 索引。

db.person.createIndex( {habbit: 1} )     // 升序创建多key索引

db.person.find({habbit: 'football'})     //查找喜欢足球的人

 

3、创建哈希索引

创建命令如下:

 

4、文本索引的创建与使用

假如我们用 Mongodb 存储了很多博客文章,那么如何快速找到所有关于 mongodb 这个主题的文章呢?这时候就要用到文本搜索了。

(1). 创建文本索引命令:

创建单个字段的文本索引

db.collection.createIndex({ title: 'text'})
  1. 创建全文本索引的字段必须为 string 格式;
  2. 每个集合只支持一个文本索引

创建多个字段的文本索引

db.collection.createIndex(

  {

     title: 'text',

     tags: 'text'

  }

)

 

(2). 使用文本索引;

现在我们已经创建了 title 的索引,我们来搜索一下含有 educoder.net 的文章:

  1. search 后的关键词可以有多个,关键词之间的分隔符可以是多种字符,例如空格、下划线、逗号、加号等,但不能是-和\,因为这两个符号会有其他用途。搜索的多个关键字是 or 的关系,除非你的关键字包含-;
  2. 匹配时不是完整的单词匹配,相似的词也可以匹配到;
db.collection.find({$text:{$search:'educoder.net'}})

(3). 删除文本索引

1.  通过命令获取索引名:

db.collection.getIndexes()

  1. 删除命令:
db.collection.dropIndex('title_text')

 

编程测试代码(部分):😊

db.article.insert([

{_id:1,title: "提升程序员工作效率的6个工具利器",tags:[ "Alfred ", "幕布"],follwers:543},

{_id:1,title:"我是如何从零开始学习前端的",tags:["HTML","Html5","CSS "],follwers:1570},

{_id:1,title: "20个非常有用的JAVA程序片段",tags:[ "Java ", "编程"],follwers:1920}])
db.article.createIndex({follwers:1,title:1})

db.article.createIndex({tags:-1})

db.article.createIndex({_id:"hashed"})

db.article.createIndex( { title:'text',tags:'text'})

db.article.getIndexes()

第三关:有趣的地理位置

相关知识:

1、GeoJson 数据

只有拥有特定格式的文档才可以创建。

如果我们用的是 2dsphere 索引,那么插入的应该是 GeoJson 数据。GeoJson 的格式如是:

     { type: ‘GeoJSON type’ , coordinates: ‘coordinates’ }

  1. type :指的是类型,可以是 Point (本例中用的,点)、LineString(线)、 Polygon(面) 等;
  2. coordinates :指的是一个坐标数组
db.locations.insert({_id:1,name:'长沙站',location:{type:'Point',coordinates:[113.018987,28.201215]}})

db.locations.insert({_id:2,name:'湖南师范大学',location:{type:'Point',coordinates:[112.946045,28.170968]}})

db.locations.insert({_id:3,name:'中南大学',location:{type:'Point',coordinates:[112.932175,28.178291]}})

db.locations.insert({_id:4,name:'湖南女子学院',location:{type:'Point',coordinates:[113.014675,28.121163]}})

db.locations.insert({_id:5,name:"湖南农业大学",location:{type:'Point',coordinates:[113.090852,28.187461]}})

2、创建地理位置索引

一般的代码:  db.集合.createIndex({创建索引的属性:  ’ 2dsphere’ })

  1. 2d :平面坐标索引,适用于基于平面的坐标计算,也支持球面距离计算,不过官方推荐使用 2dsphere 索引;
  2. 2dsphere :几何球体索引,适用于球面几何运算(一般都是用这个!!!)
  3. 默认情况下,地理位置索引会假设值的范围是从−180到180(根据经纬度设置)。

db.locations.createIndex({location:'2dsphere'})

 

3、地理位置索引的使用

查询命令:(很重要!!!)

db.runCommand({

    geoNear:'locations',

    near:{type:'Point',coordinates:[113.018987,28.201215]},   (一般是location)

    spherical:true, 

    minDistance:1000,

    maxDistance:8000

    })
  1. geoNear :我们要查询的集合名称
  2. near :就是基于那个点进行搜索,这里是我们的搜索点“长沙站”;
  3. spherical :是个布尔值,如果为 true,表示将计算实际的物理距离,比如两点之间有多少 km,若为 false,则会基于点的单位进行计算
  4. minDistance :搜索的最小距离,这里的单位是米
  5. maxDistance :搜索的最大距离。

 

编程测试代码:

db.people.insert({_id:1,name:'A',personloc:{type:'Point',coordinates:[116.403981,39.914935]}});

db.people.insert({_id:2,name:'B',personloc:{type:'Point',coordinates:[116.433733,39.909511]}});

db.people.insert({_id:3,name:'C',personloc:{type:'Point',coordinates:[116.488781,39.949901]}});

db.people.insert({_id:4,name:'D',personloc:{type:'Point',coordinates:[116.342609,39.948021]}});

db.people.insert({_id:5,name:'E',personloc:{type:'Point',coordinates:[116.328236,39.901098]}});

db.people.insert({_id:6,name:'F',personloc:{type:'Point',coordinates:[116.385728,39.871645]}});

db.people.createIndex({personloc:'2dsphere'});

db.runCommand({

    geoNear:'people',

    near:{type:'Point',coordinates:[116.403981,39.914935]},

    spherical:true,

    minDistance:100,

    maxDistance:3000

});

db.runCommand({

    geoNear:'people',

    near:{type:'Point',coordinates:[116.433733,39.909511]},

    spherical:true,

    minDistance:100,

    maxDistance:5000

});

db.runCommand({

    geoNear:'people',

    near:{type:'Point',coordinates:[116.488781,39.949901]},

    spherical:true,

    minDistance:3000,

    maxDistance:8000

});

db.runCommand({

    geoNear:'people',

    near:{type:'Point',coordinates:[116.342609,39.948021]},

    spherical:true,

    minDistance:3000,

    maxDistance:8000});

MapReduce查询:

操作语法:

db.集合名称.mapReduce(

function(){emit(key, values)},   map:key是需要聚合的属性,values是操作值的属性

function(key, values){return Array.操作(values)},  reduce:操作:sum,avg,min,max,first

{query: 条件,

out: 存储到新的集合的名称,

sort: 条件,

limit: number

}

)

进行查询操作练习:

db.educoder.mapReduce(

                     function(){emit(this.author,this.learning_num);},

                     function(key,values){return Array.avg(values)},

                     {

                     out:"avg_num"

                     }

)

db.avg_num.find()

 

db.educoder.mapReduce(

                     function(){emit(this.author,this.learning_num);},

                     function(key,values){return Array.avg(values)},

                     {

                     out:"avg_num",

                     limit:2

                     }

)

db.avg_num.find()

 

db.educoder.mapReduce(
               function(){
               emit(this.author,this.learning_num);
                        },
               function(key,values){
               return Array.avg(values)
                        },

                     {
                     query: {author: "李暾"},
                     out:"avg_num",
                     }
)

db.avg_num.find()

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐