MongoDB入门

2018-07-11  本文已影响13人  为技术疯狂

一、基本概念解释

二、MongoDB 数据类型

下表为MongoDB中常用的几种数据类型。

ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:

前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间早了 8 个小时

接下来的 3 个字节是机器标识码

紧接的两个字节由进程 id 组成 PID

最后三个字节是随机数

MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId 对象

由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

> var newObject = ObjectId()

> newObject.getTimestamp()

ISODate("2018-07-05T07:21:10Z")

ObjectId 转为字符串

> newObject.str

5a1919e63df83ce79df8b38f

三、Mongodb入门命令

3.1、基本查看命令

show dbs 查看所有的数据库

use databaseName 使用某个数据库  例如:use edu

show tables/collections 查看当前库下的所有collection

3.2、库和集合的操作

查看当前所处的数据库

db

3.3、在mongodb中,库是隐式创建的,你可以use 一个不存在的库,然后在该库下创建collection,即可创建库。

db.dropDatabase(); 删除database, 把当前所用的库给删除了 , 即使里面有数据也会删除

db.createCollection(‘collectionName’), 创建collection,collection也是允许隐式创建的

db.collectionName.insert(document); 在集合(表)中插入具体数据的时候会自动创建

db.collectionName.drop() , 删除collection

举例如下:

use edu #创建数据库:edu

db.createCollection('video') #创建集合(表):video

db.video.insert({play_url:'http://www.sohu.com/a.mp4',title:'战狼2',area:'中国'})   #插入一条数据

db.video.drop()   #删除集合video

四、Mongodb基本增删改查

4.1、增加数据

mongodb存储的是文档,文档是json格式的对象,我们向数据库存储数据的时候可以使用insert方法,数据格式要以js对象格式进行存储:

语法: db.collectionName.insert(document);

db.createCollection('student')

db.student.insert({name:'zhangsan',age:'20'})  向当前students表里插入数据

4.1.1、增加单篇文档

语法: db.student.insert({title:"nice day"});

4.1.2、增加单个文档,并且指定_ID

语法: db.student.insert({_id:8,age:78,name:"lisi"});

_id 是我们在插入数据的时候,mongodb自动给文档添加的一个属性,如果我们不需要系统分配_id ,可以在添加数据的时候手动设置,覆盖原有_id ,虽然_id 的类型可以自由指定,但是在同一个集合当中必须唯一,如果插入重复的值,系统会抛出异常.

这个_id 的名称是固定的,它可以是Mongodb支持的任何数据类型,默认是ObjectId,在关系型数据库中,主键通常是数值型的,并且可以设置自增,而Mongodb的主键,原生不支持自增主键。

4.1.3、增加多个文档

db.student.insert( [{time:'friday',value:'mongodb'},{_id:1,gender:'male',name:'QQ'}])

可以以数组的方式,一次性向集合插入多个数据;同时应该注意的是,由于mongodb采用的是 J a v a S c r ip t S he l l,所以我们可以根据js特性,将文档作为值赋给变量然后进行操作:

j = {name : 'isi'};

t = {name : 'wangwu'};

db.student.insert([j,t]);

4.1.4、SAVE和INSERT的区别

save和insert都可以进行数据的插入和增加,但是也有一些异同:

对于已存在数据 { _id:1, "name":"n1" },再次进行插入操作时,

a、insert({_id:1, "name" :"n2"}) 会报主键重复的错误提示;

b、save({ _id:1, " name ":"n2"}) 会把 n1 修改为 n2 。

相同点: 若新增的数据中没有主键时,会增加一条记录。

不同点: 主键_id已存在时 :insert 会报错,save会修改当前_id的数据

即:insert有则报错,无则插入;save有则修改,无则插入

4.2、查询操作

4.2.1、FIND()

无条件的普通查询方式很简单,可以直接使用

db.collectionName.find( ) ; 一次可以查出指定集合中的所有数据

db.student.find();

按照条件进行查询操作

语法: db.collection.find( 查询表达式 , 查询的列 ) ;

例1: db.student.find({},{name:1})  //查询student集合中的name属性 (_id属性默认总是查出来)

例2: db.student.find({},{name:1, _id:0}) //查询student集合中的name属性,且不查询_id属性此处的0表示的是false,不查询

例3: db.student.find({age:20},{name:1,_id:0 } ) ;//查询student集合中age属性值为20的name属性

4.2.2、FINDONE()

findOne()和find()函数一样,只是findOne()返回的是查询结果中的第一条数据,或者返回null.

4.3、删除操作

语法: db.collectionName.remove( 查询表达式 , 选项 );

选项是指 { justOne:true/false},是否只删一行, 默认为false 注意

1: 查询表达式依然是个json对象

2: 查询表达式匹配的行,将被删掉.

3: 如果查询表达式为空对象{},collections中的所有文档将被删掉.

例1: db.student.remove({name:'n1'});//删除stu表中name属性值为'n1'的文档

例2: db.student.remove({gender:'m'},true);//删除stu表中gender属性为m的文档,只删除1行.

4.4、修改操作

语法: db.collection.update( 查询表达式 , 新值 , 选项 );

*改哪几行? --- 查询表达式

*改成什么样? -- 新值 或 赋值表达式

*操作选项 ----- 可选参数

upsert:如果要更新的那条记录没有找到,是否插入一条新纪录,默认为false

multi  :是否更新满足条件的多条的记录,默认为false

multi :是否更新满足条件的多条的记录,false:只更新第一条,true:更新多条,默认为false

例:db.student.update({name:'QQ'},{name:'MSN'}); //是指选中student表中,name值为QQ的文档,并把其文档值改为{name:"MSN"},

结果:文档中的其他列也不见了,改后只有_id和name列了。即是新文档直接覆盖了旧文档,而不是修改。

4.4.1、修改操作中的关键字

如果是想修改文档的某列,可以用$set关键字

例:db.student.update(query,{$set:{name:’QQ’}})

修改时的赋值表达式

$set 修改某列的值

$unset 删除某个列

$inc 增长某个列

$rename 重新命名某列

$setOnInsert 当upsert为true时,并且发生了insert操作时,可以补充的字段.

$INC实例

按照指定的步长增长某个列;

db.student.insert({"uid":"201203","type":"1",size:10})

db.student.update({"uid" :"201203"},{"$inc":{"size"  :  2}})

$UNSET实例

db.student.find({_id:8})

db.student.update({_id:8},{$unset:{age:'sss'}})

4.5 查询表达式

我们无论在修改删除还是查询的过程中,都需要传入查询表达式对目标数据进行查询,表达式有很多种

1:  最简单的查询表达式

{filed:value}  ,是指查询field列的值为value的文档

2:  $ne:!=

{field:{$ne:value}} 

db.stu.find({age:{$ne:16}}) 作用--查age列的值 不等于16的文档

3:$gt:大于

$lt:小于

$gte:大于或等于

$lte:小于或等于

4:  $in:[]    查询某列的值在范围内的文档

db.goods.find({cat_id:{$in:[2,8]}}

5:  $nin:not  in      查询某列不在范围内的文档

$nin:[2,3,5]

6:  $exists

语法:  {field:{$exists:1}}

作用:  查询出含有field字段的文档

7:用正则表达式查询  以”诺基亚”开头的商品

例:db.goods.find({goods_name:/诺基亚.*/},{goods_name:1});

五 游标操作

通俗的说,游标不是查询结果,而是查询的返回资源,或者接口,通过这个接口,你可以逐条对数据进行读取;

声明游标 :

var  cursor  =  db.collectioName.find(query,projection);

cursor.hasNext()  //判断游标是否已经取到尽头 

cursor.next()  //取出游标的下1个单元

用while来循环游标

var  mycursor  =  db.bar.find({_id:{$lte:5}})

while(mycursor.hasNext())  { printjson(mycursor.next());}

游标还有一个迭代函数,允许我们自定义回调函数来逐个处理每个单元.

cursor.forEach(回调函数);

var  gettitle  =  function(obj)  {print(obj.goods_name)}

var  cursor  =  db.goods.find();

cursor.forEach(gettitle);

游标在分页中的应用

比如查到10000行,跳过100页,取10行,一般地,我们假设每页N行, 当前是page页, 就需要跳过前 (page-1)*N 行, 再取N行.

在mongo中,分页是用skip(), limit()函数来实现的

//查询结果中,跳过前9995行

var  mycursor  =  db.bar.find().skip(9995);

//查询第901页,每页10条

则是  var  mytcursor  =  db.bar.find().skip(9000).limit(10);

六 group分组

mongodb支持聚合运算;

在goods表中插入数据

db.goods.insert([

{'_id':3,'cat_id':6,'price':29},

{'_id':4,'cat_id':7,'price':30},

{'_id':5,'cat_id':6,'price':31},

{'_id':6,'cat_id':7,'price':32},

{'_id':7,'cat_id':7,'price':28},

])

如果我们所处的是mysql数据库,我们可以这样查询每个类下面的商品平均价格

select  avg(price)  from  goods  group  by  cat_id;

但如果在mongodb下,我们如何查询分组内的平均值呢? 我们需要使用mongodb的聚合运算 https://docs.mongodb.com/manual/aggregation/

db.goods.aggregate([

{$match:{}},

{$group:{_id:"$cat_id",avg:{$avg:'$price'}}}

]);

其中,$match表示匹配的条件,$group表示分组的条件,$avg表示求平均值. 当然,指令还有很多,我们还可以使用limit,sort等操作

db.goods.aggregate([

{$match:{}},

{$group:{_id:"$cat_id",avg:{$avg:'$price'}}},

{$limit:1}

]);

按照价格降序排列

db.goods.aggregate([

{$match:{}},

{$sort:{price:-1}}

]);

七 MapReduce

7.1、MapReduce原理

随着大数据兴起,MapReduce的概念也越来越火,通常的概念是用于大规模数据集(1TB)的并行运算,实际上就是传统关系型数据库的group概念的延伸.

MapReduce之所以能够流行,是因为数据的大,当数据过大的时候,单个服务器无法承载,facebook,微软等等的数据中心都是分布在世界各地的, 我们所需 要的数据很可能分布在不同的服务器甚至世界各地.在这时候,我们就无法使用group操作了.

MapReduce通俗的讲,最大的优点就是可以支持分布式的group

而MapReduce的操作即分为map和reduce两步;

map ---> 映 射

reduce ---> 减少,规约,回归

7.2、MapReduce统计价格

//按照cat_id  分配  price,把price数据映射到一个数组上 var  map  =  function(){

emit(this.cat_id  ,  this.price)

}

//将映射好的数组进行操作

var  reduce  =  function(cat_id,number){ return  Array.avg(number)

}

//将统计的数据映射到res表当中db.goods.mapReduce(map,reduce,{out:'res'})

接下来我们使用mapReduce功能实现地震数据的统计

7.3、下载并导入地震信息

在国家地震科学数据共享中心下载过去一年的地震数据 http://data.earthquake.cn/sjfw/index.html?PAGEID=datasourcelist&dt=40280d0453e414e40153e44861dd0003

将数据保存为csv格式,导入到mongodb数据库中,使用mongoimport

-d : 指明导入文件存放在哪个数据库

-c : 指明导入文件存放在哪个集合

--type:指明要导入的文件格式。

--headerline:指明不导入第一行,csv格式的文件第一行为列名。

--file:指明要导入的文件路径。

./bin/mongoimport  -d  test  -c  dz  --type  csv  --file  /usr/local/src/dz.csv  --headerline

7.4、按照经纬度统计数据

我们规约的时候按照经纬度的5*5方格进行分组,如果在此方格内存在地震,则地震+1

var  map  =  function(){

var  jd  =  parseInt(this.jd/5)*5; var  wd  =  parseInt(this.wd/5)*5; var  area  =  jd  +  ':'  +  wd;

emit(area,1);//如果该区域有地震,则统计为1

}

var  reduce  =  function(area,nums){ return  Array.sum(nums);

}

db.dz.mapReduce(map,reduce,{out:'dzrs'});

成功获取区间范围内的地震次数,此时我们要将数据导出为json,做成热力图;

7.5 热力图

使 用 百 度 地 图 开 放 平 台 的 热 力 图 api http://lbsyun.baidu.com/index.php?title=jspopular

填入密钥,生成热力图

7.6 展示地震数据

转化地震数据为规定的json格式

var  course  =  db.dzrs.find();

var  row;

course.forEach(function(obj){

    row  =  obj._id.split(':');

    db.reli.insert({lng:parseInt(row[1])+2.5,lat:parseInt(row[0])+2.5,count:obj.value})

})

导出json

./bin/mongoexport  -d  test  -c  reli  -o  /usr/local/src/reli.json

将json数据放入热力图当中并配置热力图相关选项.

上一篇下一篇

猜你喜欢

热点阅读