MonGoDB学习笔记

来源:互联网 发布:淘宝开放平台开发者 编辑:程序博客网 时间:2024/06/14 13:58
head:
mongodb单个数据库默认最多可以创建24000个名称空间,可以修改nssize参数来增加名称空间的数目限制
tips1:尽可能的去使用内嵌数据,而不是引用,因为这样高效的多,而且总是可行。另:所有的引用都会在数据库中
产生另一个查询。


1、连接mongodb
先开一个cmd界面,
进入到mongodb的bin目录,执行mongod.exe -f mongo.config
再开另一个cmd界面,进入bin目录,执行mongo.exe,连接mongoDB


2、输入db,可以看到当前连接的数据库名称
输入show dbs可以显示所有数据库名
输入use 数据库名 ,可以切换数据库
输入show collections就可以看到当前数据库下所有集合的名称


3、创建数据库
使用use 相要创建的数据库名称
如果该数据库不存在,则创建。
但是这时使用show dbs命令是找不到这个数据库的,
我们需要先在这个数据库插入一条数据,才可以看见。
插入数据命令:
db.mydb.insert({"name":"lele"})
这时,使用show dbs就可以看到这个新建的数据库了
输入db.mydb.find()可以看到这个数据库下的数据内容


4、删除数据库
需要先切换到想要删除的数据库中
use mydb
使用db命令查看当前数据库
db
使用删除数据库命令,删除当前数据库
db.dropDatabase()
在使用show dbs命令可以查看当前存在的数据库
ps:mongo的函数有大小写的区分,大小写需要都写对


5、给一个集合插入数据
db.col.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})
如果该集合不存在,则mongodb会创建该集合
也可以将插入的内容定义为一个变量
 document=({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
});
执行db.col.insert(document)命令可以插入数据
使用db.col.find()查看集合的数据
使用find命令可以有条件的查询,比如find({likes:100})相当于oracle里的where likes=100


还有一种需要特别注意:
如果是内嵌式文档结构的数据,比如数据内容如下:
notes:
[{address:"12345",addre_num:100}]
相应限定内嵌文档里的内容也是可以的,但是需要使用[.]来指定限定的字段
比如:
find({"notes.address":"12345"}),注意,平时查询的时候可以不加["]直接指定字段,
但是如果是引用内嵌文档的字段,就需要使用["]把字段内容包裹起来了


5.1、固定集合
显示的建立一个集合,需要在建立集合的时候指定集合大小,固定集合保证了集合的顺序和
集合数据的插入顺序是一直的。因为如果不是固定集合的话,在做更新操作的时候,可能会改变集合的
顺序。
PS:固定集合里面存放的数据如果超过限定大小的时候,会清除之前的数据,清楚顺序也是按照老数据先
清楚的原则。
固定集合建立语法:
db.createCollection("collectionname",{capped:true,size:1000})
这个1000不是恒定的,是可以改变的,这里表示集合大小最大不能超过1000个字节


另:如果要改变固定集合的排序方式,需要使用$natural,实例:
db.collectionname.find().sort({$natural:-1}).limit(10),
这个可以用来查看最新登陆日志信息


可以使用validate()来查看集合的状态,使用实例:
db.test.validate()
固定集合可以使用max参数来限定最大的文档数量


6、更新操作
这个语句可以更新col集合的第一条数据
db.col.update({'by':'菜鸟教程'},{$set:{'by':'fool bird'}})
如果要更新所有的语句,则需要加上multi:true
db.col.update({'by':'菜鸟教程'},{$set:{'by':'fool bird'}},{multi:true})
--PS:需要注意:{'by':'菜鸟教程'}这里需要写的和集合里一模一样,哪怕是数据类型也需要一样,
因为这里相当于update的where条件,所以如果where条件没有写对的话,则可能导致查不到需要更新
的数据,导致更新不了数据。


在更新操作中,格式如下:
db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)
其中,query表示需要更新的语句,相当于关系型数据库里的where,update则是相当于关系型数据库里的update操作的set,
upsert、multi和writeConcern则是选填
upsert为true时表示update时没有这条,则插入,
multi为true时表示更新所有的语句
writeConcern则是表示写入日志级别


官方解释:
query : update的查询条件,类似sql update查询内where后面的。
update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
writeConcern :可选,抛出异常的级别。


ps:使用db.col.find().pretty()可以显示出比较漂亮的格式来查看集合数据(这个叫做结构化读取数据)




还有另一种更新方式
使用save命令
先找到需要更新的数据的_id,
然后定义一个变量:
document1=({
"_id" : ObjectId("5763a7cab0b96bb88a2291d3"),
    "title" : "MongoDB",
    "description" : "MongoDB 是一个 Nosql 数据库",
    "by" : "Runoob",
    "url" : "http://www.runoob.com",
    "tags" : [
            "mongodb",
            "NoSQL"
    ],
    "likes" : 110
})
使用save命令更新所有数据,
db.col.save(document1)
PS:save可以做一次性插入,或者用作更新,不能作为多次插入的命令。
因为一个文档使用save插入到集合里,这个文档的唯一标识'_id'就会变成插入的
这条数据的唯一标识,就算多次执行save命令的话,也是更新这个文档数据,并不会有多次insert的效果。
而且document1使用save执行了一次,就不能使用document1多次insert了,不然会造成唯一标识冲突


更多的更新实例(PS:$inc的意思是给数字类型的字段加上后面对应的数字)
只更新第一条记录:
db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );
全部更新:
db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );
只添加第一条:
db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
全部添加加进去:
db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );
全部更新:
db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );
只更新第一条记录:
db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );




7、移除数据
官方格式:
db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)
具体删除语句:
db.col.remove({'likes':110},1)
语句意思:查询到likes=110的数据,只删除一条,1变成true意思也是一样的


如果要删除全部数据
db.col.remove({}),相当于oracle里的truncate


8、查询文档
命令如下:
db.col.find():非结构化显示集合col的所有数据
db.col.find().pretty():结构化的显示集合col的所有数据
db.col.findOne():结构化的显示集合col的一条数据


一些比较符的使用:
如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:
操作         格式                    范例                                        RDBMS中的类似语句
等于       {<key>:<value>}         db.col.find({"by":"菜鸟教程"}).pretty()   where by = '菜鸟教程'
小于       {<key>:{$lt:<value>}}   db.col.find({"likes":{$lt:50}}).pretty()    where likes < 50
小于或等于 {<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty() where likes <= 50
大于       {<key>:{$gt:<value>}}   db.col.find({"likes":{$gt:50}}).pretty()    where likes > 50
大于或等于 {<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty() where likes >= 50
不等于     {<key>:{$ne:<value>}}   db.col.find({"likes":{$ne:50}}).pretty()    where likes != 50


多个条件,相当于where里的and
db.col.find({key1:value1, key2:value2}).pretty()
实例:
db.col.find({"by":"菜鸟教程", "title":"MongoDB 教程"}).pretty()


or的语法
db.col.find(
   {
      $or: [
     {key1: value1}, {key2:value2}
      ]
   }
).pretty()
实例:
db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()


and和or联合使用
实例:
db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
相当于:where likes>50 AND (by = '菜鸟教程' OR title = 'MongoDB 教程')




MongoDB 条件操作符(20160617)


db.col.find({'likes':{$gt:100},'likes':{$lt:200}})和db.col.find({'likes':{$gt:100,$lt:200}})区别在哪里?
第二个相当于sql里的:
likes>100 and likes <200 ,
而第一个则是会让第二个条件覆盖第一个条件,查询出来的结果也是按照第二个条件出来的结果。


9、$type 操作符
类型 数字 备注
Double 1  
String 2  
Object 3  
Array 4  
Binary data 5  
Undefined 6 已废弃。
Object id 7  
Boolean 8  
Date 9  
Null 10  
Regular Expression 11 
JavaScript 13  
Symbol 14  
JavaScript (with scope) 15 
32-bit integer 16 
Timestamp 17  
64-bit integer 18 
Min key 255 Query with -1.
Max key 127  


使用实例:
db.col.find({'likes':{$type:2}})--取集合中likes字段是string类型的文档


10、MongoDB Limit与Skip方法


就像是oracle的rownum和hive的limit一样,mongodb也是有自己的limit(number)命令的


使用实例:
db.col.find().limit(2)--这里的2表示显示几行数据,如果没有指定limit默认find()命令是展示所有数据


还有一个就是skip(number)命令,可以用于跳过几行不显示


使用实例:
db.col.find().limit(2).skip(1)--这里指的是跳过第一行数据不读,执行顺序应该是先skip再limit,
这里不是先限完两行,再跳过读出来的两行中的一行不显示的。但是跳过条数过多就会不显示了


11、MongoDB sort()方法
在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,
并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。


使用实例:
db.col.find().sort({'likes':1})--升序
db.col.find().sort({'likes':-1})--降序


PS: 如果没有指定sort()方法的排序方式,默认按照文档的升序排列。


PS2:如果指定排序的字段不存在或者没有使用排序的话,默认展示的顺序则是按照数据插入的时间展示


12、创建索引


实例:
db.col.ensureIndex({'likes':1},{background:true})--参数background等于true意思是在后台执行创建索引的过程,
而在likes后面的1表示按照升序的方式来建立索引


查看集合的索引信息:
db.runobb.getIndexes()


mongoDB默认给_id建立一个索引,然后使用上面的命令可以查看到我们新建的另一个索引信息


13、聚合函数
aggregate() 方法
MongoDB中聚合的方法使用aggregate()。


count(1)实例如下:
db.col1.aggregate([{$group:{_id:"$by_user",nums:{$sum:1}}}])
PS:_id后面接的字段是用来进行group的字段,需要使用$标记出来
$sum是聚合函数,类似select by_user,sum(1) from col1 group by by_user 


 db.col1.aggregate([{$group:{_id:"$by_user",nums:{$sum:'$likes'}}}])
 则是group by by_user ,聚合字段likes的值
 
 
同理,下面分别是求平均值、求最大值、求最小值的聚合函数:
db.col1.aggregate([{$group:{_id:"$by_user",nums:{$avg:'$likes'}}}])
db.col1.aggregate([{$group:{_id:"$by_user",nums:{$max:'$likes'}}}])
db.col1.aggregate([{$group:{_id:"$by_user",nums:{$min:'$likes'}}}])




一般的的find命令都是显示所有的字段数据,
有点类似oracle的select * from ,下面介绍一个命令,
可以限定字段显示数据
db.col1.aggregate({$project:{by_user:1,url:1}})--默认是有_id字段的,所以这句命令相当于select _id,by_user,url from col1;
db.col1.aggregate({$project:{_id:0,by_user:1,url:1}})--这里用_id:0去掉了_id字段的显示,相当于select by_user,url from col1;


db.col1.aggregate([{$match:{'likes':{$gt:5,$lt:105}}},{$group:{_id:null,count:{$sum:1}}}])
相当于把likes大于5小于105的做了个统计,然后到group上进行count


aggregate也有skip命令,
实例如下:
db.col1.aggregate({$skip:3})--跳过条数过多也会不显示的




14、mongoDB复制(主从配置)


MongoDB副本集设置
在本教程中我们使用同一个MongoDB来做MongoDB主从的实验, 操作步骤如下:
1、关闭正在运行的MongoDB服务器。
现在我们通过指定 --replSet 选项来启动mongoDB。--replSet 基本语法格式如下:
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
实例
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。
启动后打开命令提示框并连接上mongoDB服务。
在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。
我们可以使用rs.conf()来查看副本集的配置
查看副本集姿态使用 rs.status() 命令
副本集添加成员
添加副本集的成员,我们需要使用多条服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。
语法
rs.add() 命令基本语法格式如下:
>rs.add(HOST_NAME:PORT)
实例
假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:
>rs.add("mongod1.net:27017")
>
MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。
MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。




15、mongoDB的备份与恢复(有疑问20160620)
在mongoDB的bin目录执行mongodump,会在当前目录生成一个dump文件夹,
在dump文件夹会有数据库实例的文件夹,有几个数据库实例就有几个文件夹




mongoDB恢复
在mongoDB的bin目录执行mongorestore,会默认找到当前目录的dump文件夹内容,
进行恢复


16、MongoDB 监控
mongoDB状态监控
在mongoDB的bin目录下,执行命令mongostat可以查看到mongoDB的运行状态
(mongostat是mongodb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现
数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。)


查看数据库实例花费时间,mongotop:
mongotop也是mongodb下的一个内置工具,mongotop提供了一个方法,用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在读取和写入数据。
 mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回值的每一秒。
也可以使用mongotop 10,后面跟的10指的是等待时间,默认是每一秒返回一次,加入参数指的是每10秒返回


mongotop输出结果说明:
输出结果字段说明:
ns:
包含数据库命名空间,后者结合了数据库名称和集合。
db:
包含数据库的名称。名为 . 的数据库针对全局锁定,而非特定数据库。
total:
mongod花费的时间工作在这个命名空间提供总额。
read:
提供了大量的时间,这mongod花费在执行读操作,在此命名空间。
write:
提供这个命名空间进行写操作,这mongod花了大量的时间。


17、查看MongoDB某个数据库下的所有集合
show collections


18、查看集合里数组的数据
集合数据:
> db.user.findOne({'address.pincode':123456})
{
        "_id" : ObjectId("5768e9e91f4bc87c5032122c"),
        "contact" : "987654321",
        "dob" : "01-01-1991",
        "name" : "Tom Benzamin",
        "address" : [
                {
                        "building" : "22 A, Indiana Apt",
                        "pincode" : 123456,
                        "city" : "Los Angeles",
                        "state" : "California"
                },
                {
                        "building" : "170 A, Acropolis Apt",
                        "pincode" : 456789,
                        "city" : "Chicago",
                        "state" : "Illinois"
                }
        ]
}
实例:
 db.user.findOne({'address.pincode':123456},{'address.building':1,'address.city':1})
前面是筛选条件,后面是指定显示的字段


上面的语句是先查询,后指定字段内容。而db.col.find({key1:value1, key2:value2}).pretty()
这个语句是里面是做了筛选,条件相当于where里的key1=value1 and key2=value2


19、一些命令符的使用
$in 效果同sql里的in,相当于某个字段取一个范围的值
$nin  效果同sql里的not in,相当于某个字段不取一个范围的值
$not  取反
$mod  实例:$mod:[11,0],$mod会将查询的值除以第一个给定的值,若余数等于第二个给定的值,则返回该结果
##请注意 $exists 无法利用到索引, 但$NE 可以用上索引, 所以处于性能的考虑尽可能用 $ne:null
$exists  存在  实例:db.mycollection.find({"IMAGE URL":{$exists:true}});
$ne    不等于  实例:db.mycollection.find({"IMAGE URL":{$ne:null}});


20、定义变量赋值时候注意事项
var ids=db.user1.find({'name':'Tom Benzamin'},{'address_ids':1})
var ids=db.user1.findOne({'name':'Tom Benzamin'},{'address_ids':1})


这两种赋值方式,第一种是一次性的(看结果是一次性的),即执行完以后,单独执行ids可以显示一次结果,
后续再执行ids则不再显示了。
第二张是可以在本窗口界面多次执行的,即在本窗口多次执行都可以看到对应的值


21、数据库引用
我们在调用不同地址时,也需要指定集合,一个文档从多个集合引用文档,我们应该使用 DBRefs。
DBRef的形式:
{ $ref : , $id : , $db :  }
三个字段表示的意义为:
$ref:集合名称
$id:引用的id
$db:数据库名称,可选参数


实例:
{
   "_id":ObjectId("53402597d852426020000002"),
   "address": {
   "$ref": "address_home",
   "$id": ObjectId("534009e4d852427820000002"),
   "$db": "w3cschoolcc"},
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin"
}


使用:
>var user = db.users.findOne({"name":"Tom Benzamin"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})


最后一步得到数据:
{
   "_id" : ObjectId("534009e4d852427820000002"),
   "building" : "22 A, Indiana Apt",
   "pincode" : 123456,
   "city" : "Los Angeles",
   "state" : "California"
}




这里有一个问题,为什么使用db[dbRef.$ref].findOne({"_id":(dbRef.$id)})命令得到最后一步结果
需要切换到address存在的数据库下?


22、覆盖索引查询
所有出现在查询语句中的字段都是索引的一部分,由于索引是存放在ram上的,
所以效率特别高。直接从索引中就把数据拿去了。


实例:
{
   "_id": ObjectId("53402597d852426020000002"),
   "contact": "987654321",
   "dob": "01-01-1991",
   "gender": "M",
   "name": "Tom Benzamin",
   "user_name": "tombenzamin"
}


建立索引:
db.users.ensureIndex({gender:1,user_name:1})


覆盖式查询:
db.users.find({gender:"M"},{user_name:1,_id:0})


下列语句不是覆盖所有查询(_id不也是一个索引么?覆盖索引查询不能夸索引么?):
db.users.find({gender:"M"},{user_name:1})


限制条件:
所有索引字段是一个数组
所有索引字段是一个子文档




23、 查询分析
explain不能和findOne混用
使用 explain()
db.users.find({gender:"M"},{user_name:1,_id:0}).explain()
indexOnly: 字段为 true ,表示我们使用了索引。
cursor:因为这个查询使用了索引,MongoDB中索引存储在B树结构中,所以这是也使用了BtreeCursor类型的游标。如果没有使用索引,游标的类型是BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。
n:当前查询返回的文档数量。
nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。
millis:当前查询所需时间,毫秒数。
indexBounds:当前查询具体使用的索引。




24、使用 hint()
使用hint可以强制走某个索引
db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})


25、
Math.random()随机数
db.col3.find().itcount(),统计记录数


26、
PS:MongoDB是文档型数据库,但是可以把MongoDB变成内存数据库,只需要把mongoDB的dbpath指定到内存文件里就可以,
让mongoDB落文件直接落到内存里,内存文件:tmpfs这是一种完全存在于内容的文件


27、
stats()查看集合状态
几个参数说明(单位是k):
avgObjSize文档平均大小
storageSize文档总的大小
indexSizes索引大小


28、基于地理位置
mongoDB可以做基于地理位置的查询,
比如给定一个点,可以找到周围几公里的坐标
或者一个区域


29、三大函数
count():用于统计集合内文档的数量
实例:
db.test.find().count()
如果想统计使用skip后的文档条数,则需要如下操作:
db.test.find().skip(2).count(true)
如果不加true的话,统计的条数依旧是集合所有文档的条数


MongoDB 原子操作(20160623)
原创粉丝点击