六、MongoDB 进阶

  • 通过数据库命令使用高级特性
  • 使用一种特殊的集合——固定大小的集合
  • 使用GridFS存储大文件
  • 利用MongoDB对服务端JavaScript的支持
  • 理解何为数据库引用,何时应该引用
一、数据库命令
在MongoDB中对文档的创建、读取、更新、删除都是基本操作。除了这些操作,其他操作都是作为命令实现的。
 
1、命令的工作原理
MongoDB中的命令其实是作为一种特殊类型的查询来实现的,这些查询针对$cmd集合来执行。
如:
-------------------------------
## 对集合进行drop操作
> db.runCommand({"drop":"test"})
{
        "nIndexesWas" : 1,
        "msg" : "indexes dropped for collection",
        "ns" : "test.test",
        "ok" : 1
}
## 实际上是这样的
> db.$cmd.findone({"drop":"test"})
-------------------------------
当MongoDB服务器得到查询$cmd集合的请求时,会启动一套特殊的逻辑来处理,而不是交给普通的查询代码来执行。
 
2、命令参考
  • db.listCommands()  获得所有命令的最新列表(或者浏览管理员接口http://localhost:28017/_commands
  • buildInfo 管理专用命令,返回MongoDB服务器的版本号和主机的操作系统 {"buildInfo" : 1}
  • collStats 返回指定集合的统计信息,包括数据大小、已分配的存储空间和索引的大小 {"collStats" : collection}
  • distinct 列出指定集合中满足查询条件的文档的指定键的所有不同的值 {"distinct" : collection, "key" : key, "query" : query}
  • drop 删除集合的所有数据 {"drop" : collection}
  • dropDatabase 删除当前数据库的所有数据 {"dropDatabase" : 1}
  • dropIndexes 删除集合里面名称为name的索引,如果名称为"*",则删除全部索引 {"dropIndexes" : collection, "index" : name}
  • findAndModify
  • getLastError 查看对本集合执行的最后一次操作的错误信息或者其他状态信息
  • isMaster 检查本服务器是主服务器还是从服务器 {"isMaster" : 1}
  • listDatabases 管理专员命令,列出服务器上所有的数据库 {"listDatabases" : 1}
  • ping 检查服务器链接是否正常 {"ping" : 1}
  • renameCollection 将基本a重命名为b,其中a和b都必须是完整的集合命名空间(如:"test.ysq")
  • repairDatabase 修复并压缩当前数据库,这个操作可能非常耗时{"repairDatabase" : 1}
  • serverStatus 返回这台服务器的管理统计信息 {"serverStatus" : 1}
二、固定集合
前面介绍的集合都是普通集合。
MongoDB还支持另外一种集合——固定集合。
固定集合就像环状队列,如果空间不足,最早的文档就会被删除,为新的文档腾出空间。
固定集合不能删除文档,更新不能导致文档移动。
固定集合和普通集合的区别:固定集合没有索引,即便是"_id"上也没有。
 
1、固定集合的特性
  • 固定集合的插入速度极快。当插入操作时,如需额外分配空间,服务器也不必查询空闲列表来放置文档,直接将文档插入集合的“末尾”就行了(如有必要就将旧的覆盖)。也无须更新索引。
  • 按照插入顺序输出的查询速度极快,因为文档本身就是按照插入顺序存储的。
  • 固定集合能够在新数据插入时,自动淘汰最早的数据。
以上三个特性组合起来使得固定集合特别适合日志这种应用场景。
事实上,MongoDB中设计固定集合的目的就是用来存储内部的复制日志oplog
 
2、创建固定集合
-------------------------------
## 创建一个固定集合staticColl, 大小
> db.createCollection( "staticColl" ,   { capped : true, size : 100000  } );
{ "ok" : 1 }
## 将已有的普通集合转换为固定集合
> db.runCommand({convertToCapped : "ysq", size : 10000}) ;
{ "ok" : 1 }
-------------------------------
 
3、自然排序
固定集合有种特殊的排序方式,叫做自然排序——文档在磁盘上的顺序。
-------------------------------
## 按照自然排序的方向顺序查询
> db.staticColl.find().sort( "$natural" ,    - 1 );
-------------------------------
 
4、尾部游标
一种特殊的持久游标,这类游标不会在没有结果后销毁。
 
三、GridFS :存储文件
GridFS是一种在MongoDB中存储大二进制文件的机制。使用GridFS存文件有如下几个原因:
  • 利用GridFS可以简化需求。要是已经用了MongoDB,GridFS就可以不需要使用独立文件存储架构
  • GridFS会直接利用也已建立的复制或分片机制,所以对于文件存储来说故障恢复和扩展都很容易
  • GridFS可以避免用于存储用户上传内容的文件系统出现的某些问题。例如:GridFS在同一个目录下放置大量的文件是没有任何问题的
  • GridFS不产生磁盘碎片,因为MongoDB分配数据文件空间时以2GB为一块
1、开始使用GridFS:mongofiles
实用程序mongofiles内置在MongoDB发布版中,可以用来在GridFS中上传、下载、列示、查找或删除文件。
-------------------------------
# 准备文件
D :\mongodb\bin > echo "hello,world" > foo.txt
 
# 上传文件
D :\mongodb\bin >mongofiles put foo.txt
connected to : 127. 0. 0. 1
added file : { _id : ObjectId( '51ca72f7ffcd1367d39b5fde'), filename : "foo.txt", chunkSize : 262144, uploadDate : new Date( 1372222199210), md5 : "c9b563d25c882c74d9ee6d2bee21949e", length : 16 }
done !
 
# 列示文件
D :\mongodb\bin >mongofiles list
connected to : 127. 0. 0. 1
foo.txt 16
 
# 查找文件
D :\mongodb\bin >mongofiles get foo.txt
connected to : 127. 0. 0. 1
done write to : foo.txt
 
D :\mongodb\bin >type foo.txt
"hello,world"
 
# 删除文件
D :\mongodb\bin >mongofiles delete foo.txt
connected to : 127. 0. 0. 1
done !
-------------------------------
 
2、内部原理
GridFS是一个建立在普通MongoDB文档基础上的轻量级文件存储规范。MongoDB服务器实际上对GridFS请求没什么热别照顾,所有相关工作都由客户端驱动或者工具来完成。
 
GridFS的一个基本思想就是可以将大文件分成很多块,没块作为一个单独的文档存储,这样就能存储大文件了。由于MongoDB支持在文档中存储二进制数据,可以最大限度减少块的存储开销。
 
另外,除了存储文件本身的块,还有一个单独的文档用来存储分块的信息和文件的元数据。
默认情况下,块将使用fs.chunks集合
-------------------------------
> db.fs.chunks.findOne();
{
          "_id" : ObjectId( "51ca772a49e548fa3e22f1cc" ),
          "files_id" : ObjectId( "51ca772a8d856c0e31946f7b" ), # 包含这个块元数据的文件文档的_id
          "n" : 0 , # 块编号
          "data" : BinData( 0 , "ImhlbGxvLHdvcmxkIiANCg==" ) # 组成块的二进制数据
}
> db.fs.files.findOne()
{
         "_id" : ObjectId( "51ca772a8d856c0e31946f7b"),
         "filename" : "foo.txt",
         "chunkSize" : 262144, # 每块大小,默认25K
         "uploadDate" : ISODate( "2013-06-26T05:07:54.012Z"),
         "md5" : "c9b563d25c882c74d9ee6d2bee21949e", # 文件内容的md5检验和,由服务器端生成
         "length" : 16 # 文件内容总的字节数
}
>
-------------------------------
 
四、服务器端脚本
在服务器端可以通过db.eval函数执行JavaScript脚本。也可以把Javascript脚本保存在数据库中,然后用别的数据库命令调用。
 
1、db.eval
db.eval可以用来模拟多文档事务:db.eval锁住数据库,然后执行Javascript,在解锁。
虽然没有内置的回滚机制,但这的确能保证一系列操作安装执行顺序发生(除非出错)。
 
-------------------------------
# 发送代码的两种方式
> db.eval( "return 1;") #不封装
1
> db.eval( "function(){return 1;}") # 封装进一个函数
1
> db.eval( "function(a){return a[0]+a[1];}",[ 1, 2]) # 传递参数
3
> db.eval( "function(a,b){return a+b;}",[ 1, 2]) # 有些版本是这样传的
-------------------------------
只有需要传递参数时,才必须封装成一个函数
 
2、存储JavaScript
集合system.js是用来存放JavaScript变量或Javascript代码的。
-------------------------------
> db.system.js.insert({ "_id" : "x", "value" : 1})
> db.system.js.insert({ "_id" : "y", "value" : 2})
> db.system.js.find()
{ "_id" : "x", "value" : 1 }
{ "_id" : "y", "value" : 2 }
> db.eval( "return x + y;")
3
> db.system.js.insert({ "_id" : "add", "value" : function(a){ var r = 0; for(var i = 0; i < a.length; i ++){ r = r + a[i]; } return r;  }});
> db.system.js.find()
{ "_id" : "add", "value" : function __cf__2__f__anonymous_function(a) {
    var r = 0;
     for (var i = 0; i < a.length; i ++) {
        r = r + a[i];
    }
    return r;
} }
> db.eval( "return add(1,2);")
0
> db.eval( "return add([1,2]);")
3
-------------------------------
 
3、安全性
类似关系型数据库的注入式攻击:
-------------------------------
> func = "function() {print('Hello, " + username + "!')}"
# 传入"'); db.dropDatabase(); print('"
> func = "function() {print('Hello, " + '); db.dropDatabase(); print(' + "!')}"
-------------------------------
 
五、数据库引用(DBRef)
(略)
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值