mongo基本操作(转)

时间:2022-09-16 15:51:55

概述

一个mongod服务可以有建立多个数据库,每个数据库可以有多张表,这里的表名叫collection,每个collection可以存放多个文档document,每个文档都以BSON(binary json)的形式存放于硬盘中,因此可以存储比较复杂的数据类型。它是以单文档为单位存储的,你可以任意给一个或一批文档新增或删除字段,而不会对其它文档造成影响,这就是所谓的schema-free,这也是文档型数据库最主要的优点。跟一般的key-value数据库不一样的是,它的value中存储了结构信息,所以你又可以像关系型数据库那样对某些域进行读写、统计等操作。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。Mongo还可以解决海量数据的查询效率,根据官方文档,当数据量达到50GB以上数据时,Mongo数据库访问速度是MySQL10 倍以上。

BSON

BSON是Binary JSON 的简称,是一个JSON文档对象的二进制编码格式。BSON同JSON一样支持往其它文档对象和数组中再插入文档对象和数组,同时扩展了JSON的数据类型。如:BSON有Date类型和BinDate类型。

BSON有以下三个特点: 轻量级、跨平台、效率高

命令

管理:

[plain]  view plain copy
  1. use admin   #进入数据库admin  
  2. db.addUser('name','pwd')    #增加或修改用户密码  
  3. db.system.users.find() #查看用户列表  
  4. db.auth('name','pwd')    #用户认证  
  5. db.removeUser('name')    #删除用户  
  6. show users   #查看所有用户  
  7. show dbs    #查看所有数据库  
  8. show collections   #查看所有的collection  
  9. db.printCollectionStats()   #查看各collection的状态  
  10. db.printReplicationInfo()    #查看主从复制状态  
  11. db.repairDatabase()    #修复数据库  
  12. db.setProfilingLevel(1)   #设置记录profiling,0=off 1=slow 2=all  
  13. show profile   #查看profiling  
  14. db.copyDatabase('mail_addr','mail_addr_tmp')   #拷贝数据库  
  15. db.mail_addr.drop()    #删除collection  
  16. db.dropDatabase()   #删除当前的数据库  

插入

插入主要有save和insert,它们的区别是,当传入给save的记录含有_id字段时,save会做更新操作,否则和insert一样做插入操作

[plain]  view plain copy
  1. db.foo.insert({'name':'tony'})    #插入一条记录,也可以批量插入,即传递一个数组即可  
  2. db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})    #存储嵌套的对象  
  3. db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})    #存储数组对象  

删除

[plain]  view plain copy
  1. db.foo.remove({'yy':5}) #删除yy=5的记录  
  2. db.foo.remove() #删除一个集合所有的记录,集合本身和索引不删除  

更新

[plain]  view plain copy
  1. db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)    #根据query条件修改,如果不存在则插入,允许修改多条记录  
  2. db.foo.update({'name':'joe'},{'$unset':{'email':1}})   #找到name为joe的记录并删除email字段  

修改器

  • $set 和 $unset:修改字段值和删除字段;
  • $rename,修改字段名字,db.students.update({_id:1},{$rename:{'nickname':'alias','cell':'mobile'}})
  • $inc:数字类型字段增减,db.user.update({'name':'owen'},{'$inc':{'age':1}});
  • $push和$pushAll:向数组类型末尾追加数据,字段不存在则创建;
  • $addToSet:向数组类型追加数据时避免重复;
  • $each:遍历数组;
  • $pop:从数组中删除数据,{$pop:{key:1}}从末尾删除数据,-1从头部删除;
  • $pull和$pullAll:从数组中删除指定数据,db.list.update({},{$pull:{'todo':'undo'}});
  • 数组定位修改器:数组可以通过下标定位,也可以通过’$‘定位查询匹配到的记录,db.blog.update({'comments.author':'joe'},{'$set':{'comments.$.author':'jim'}}); 

返回已更新的文档

findAndModify,这个命令能根据查询条件找到相应的记录并对一条结果做更新操作:

[plain]  view plain copy
  1. db.blog.findAndModify({'query':{'name':'jim'},'sort':{'age':1},'remove':true,'new':true});  
其中query为查询条件,sort指定排序,remove表示删除(remove和update不能同时指定),new表示返回更新之前还是之后的结果,这条命令只能返回一条结果。

查询

 $gt : > ,$lt : < ,$gte: >= ,$lte: <= ,$ne : !=、<> ,$or,$in : in ,$nin: not in ,$all: all ,$not: 反匹配。

[plain]  view plain copy
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});  
  2. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});  
  3. db.users.find({age: {$in: [20,22,24,26]}});  
  4. db.usets.find({'$or':[{'name':'jim','address':'china'}]});  
  5. db.users.find('this.age % 10 == 0');   
  6. db.users.find({age : {$mod : [10, 0]}});  
  7. db.users.find({favorite_number : {$all : [6, 8]}}); #多元素匹配,可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } ,查询不出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }  
  8. db.users.find({name: {$not: /^B.*/}});  
  9. db.users.find({age : {$not: {$mod : [10, 0]}}}); #查询 age取模10不等于0 的数据   
find查询时会返回匹配记录的所有字段(_id字段总是会被返回),我们可以指定只返回需要的字段,比如: 

[plain]  view plain copy
  1. db.users.find({}, {age:1}); #0为false,表示不返回, 非0为true,表示需要返回  
  2. db.users.find({}, {age:3});   
  3. db.users.find({}, {age:true});   
  4. db.users.find({ name : "bruce" }, {age:1});   
  5. db.users.find({ name : "bruce" }, {age:1, address:1});  
  6. db.users.find({}, {age:0, address:false});   
  7. db.users.find({ name : "bruce" }, {age:0, address:false});  

字段值和类型相关查询:

[plain]  view plain copy
  1. db.users.find({favorite_number: {$size: 3}}); #匹配{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }  
  2. db.users.find({name: {$exists: true}});  #查询所有存在name字段的记录  
  3. db.users.find({phone: {$exists: false}});#查询所有不存在phone字段的记录  
  4. db.users.find({name: {$type: 2}}); #查询所有name字段是字符类型的,http://docs.mongodb.org/manual/reference/operator/type/#_S_type 中有数据类型和代表数字的说明   
  5. db.users.find({age: {$type: 16}});#查询所有age字段是整型的  
  6. db.users.find({name: /^b.*/i});#查询以字母b或者B带头的所有记录   
  7. db.users.find({age: {$gt: 18}}); #查询 age > 18 的记录,以下查询都一样   
  8. db.users.find({$where: "this.age > 18"});   
  9. db.users.find("this.age > 18");   
  10. f = function() {return this.age > 18} db.users.find(f);  
对结果排序

[plain]  view plain copy
  1. db.users.find().sort({age: 1}); #以年龄升序asc   
  2. db.users.find().sort({age: -1});#以年龄降序desc   
限制返回数据条数:

[plain]  view plain copy
  1. db.users.find().limit(5); #返回5条记录  
  2. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); #返回3条记录并打印信息  
  3. db.users.find().skip(3).limit(5);#从第3条记录开始,返回5条记录(limit 3, 5)   
  4. db.users.find().count();   
  5. db.users.find({age:18}).count();   
  6. db.users.find().skip(10).limit(5).count(); #以下返回的不是5,而是user表中所有的记录数量  
  7. db.users.find().skip(10).limit(5).count(true);#如果要返回限制之后的记录数量,要使用count(true)或者count(非0)  

返回一段数据:$slice

[plain]  view plain copy
  1. db.users.find({'name':'jim'},{'school':{'$slice':3}})   #返回jim读过学校的前三所  
  2. db.users.find({'name':'jim'},{'school':{'$slice':[2,3]}})    
游标,主要用来做迭代

[plain]  view plain copy
  1. var cursor = db.people.find();  
  2. cursor.forEach(function(x){  
  3.    print(x.name)  
  4. });  

索引

mongo索引与关系型数据库的索引基本类似,所以涉及到的一些机制原理就不在这里叙述了,这里主要描述mongo索引的相关操作和需要注意的地方。

索引管理

创建索引

[plain]  view plain copy
  1. db.users.ensureIndex({'firstname':1,'lastname':1},{'name':'idx_name'});  
在字段firstname和lastname上创建了一个名为idx_name的联合索引,创建索引时值1表示索引结构中该字段升序排列,-1为倒序。
[plain]  view plain copy
  1. db.users.ensureIndex({'username':1},{'unique':true});  
在字段username上创建了一个唯一索引,所以在插入重复的username值时会出错,需要注意的时,如果插入一条记录没有username字段时,该记录的username会被赋值为null并被加入到索引中,所以同样不能插入两条没有username字段的记录。
[plain]  view plain copy
  1. db.users.ensureIndex({'username':1},{'unique':true,'dropDups':true});  
在创建唯一索引时添加dropDups字段表示如果有重复的索引字段,只保留第一条记录,其它记录会被删除。
[plain]  view plain copy
  1. db.users.ensureIndex({'username':1},{'background':true});  
在生产环境对已有数据添加索引时,注意加上background选项,它会让生成索引的过程非阻塞其它请求。
查看索引
[plain]  view plain copy
  1. db.foo.getIndexes()  
  2. db.foo.getIndexKeys()  
删除索引
[plain]  view plain copy
  1. db.foo.dropIndex('username_1')  

使用explain和hint

[plain]  view plain copy
  1. db.users.find().explain()  
使用explain可以返回查询使用的索引、查询时间和扫描行数等相关统计信息,输出的信息里重点关注cursor,n,nscanned和millis四个数据,分别说面了查询是否使用了索引,查询返回的记录数,查询扫描的记录数和开销时间,在使用索引的情况下,n和nscanned数值越接近说明索引效率越好。
使用hint强制查询使用某个索引:
[plain]  view plain copy
  1. db.users.find().hint({'username':1})  

地理空间索引

地理空间索引为针对坐标平面查询提供了专门的索引,可以很方便的找到距离当前位置最近的场所。

既然是针对平面坐标的索引,所以建立索引的键必须某种形式的一对值,比如说最常见的经度,维度。下面看看如何创建:

[plain]  view plain copy
  1. db.map.ensureIndex({'gps':'2d'},{'min':-1000,'max':1000})  
注意,创建地理空间索引时,索引值不再是1或者-1,二是2d。min和max指定了平面的范围,默认是-180~180。

gps的值可以是包含两个值的数组或者内嵌文档,比如:

[plain]  view plain copy
  1. {'gps':[0,100]}  
  2. {'gps':{'x':-30,'y':30}}  
根据位置查询:
[plain]  view plain copy
  1. db.map.find({'gps':{'$near':[10,10]}})  
默认返回100条记录,结果按由近到远排序;
[plain]  view plain copy
  1. db.runCommand({geoNear:'map',near:[10,10],num:10})  
geoNear命令还会返回每个文档到查询点的距离。
除了可以距离查找外还可以范围查找:
[plain]  view plain copy
  1. db.map.find({gps:{$within:{$box:[[0,0],[35,35]]}}})  
  2. db.map.find({gps:{$within:{$center:[[0,0],20]}}})  
$box指定在一个矩形内查找,两个坐标指定了矩形的左下角和右上角。$center指定了在一个圆内查找,给定圆心和半径。