数据库命令
MongoDB除了支持创建、读取、更新、删除文档。还支持大量的高级操作。这些操作都是用命令实现的。
命令的工作原理
MongoDB中的命令其实是作为一种特殊类型的查询来实现的,这些查询对$cmd
集合来执行,runCommand
仅仅是接受命令文档,执行等价查询,
当MongoDB服务器得到查询$cmd
集合的请求时,会启动一套特殊的逻辑来处理,而不是交给普通的查询代码来执行。几乎所有MongoDB驱动程序都提供一个类似于runCommand
的帮助方法来执行命令,但是如果有必要,总是可以使用一个简单查询的方式来运行命令。
固定集合
MongoDB还支持另外一种集合——固定集合,要事先创建,而且大小固定。 固定集合很像环形队列,如果空间不足,最早的文档就会被删除,为新的文档腾出空间。这意味着固定集合在新文档插入的时候自动淘汰新的文档。
固定集合和普通集合还有一个区别,就是在默认情况下固定集合没有索引,即便是
_id
上也没有索引。
属性及用法
固定集合的功能与限制合二为一,有一些有趣的特性。
-
对固定集合进行插入速度极快。做插入操作时,无须额外分配空间。
-
按照插入顺序输出的查询速度极快。因为文档本身就是按照插入顺序存储的。
-
固定集合能够在新数据插入时,自动淘汰最早的数据。
插入快速,按照插入顺序查询也快速、自动淘汰,这几样组合起来使得固定集合特别适合像日志这种应用场景。
事实上,MongoDB中设计规定集合的目的就是用来讯处内部复制日志oplog。固定集合还有一个很好的用法,就是缓存少量的文档。
一般来说,固定集合适用于任何想要自动淘汰过期属性的场景,没有太多的操作限制。
创建固定集合
固定集合必须在使用前显式地创建。使用create
命令创建。在shell
中,可以使用createCollection
来创建:
> db.createCollection("my_collection", {capped: true, size: 100000})
{ "ok" : 1 }
> db.createCollection("my_collection", {capped: true, size: 100000, max:100})
还可以通过转换已有的普通集合的方式来创建固定集合。使用convertToCapped
命令来完成这个操作。
> db.runCommand({convertToCapped: "foo", size:10000, max:100})
{ "ok" : 1 }
自然排序
固定集合中有种特殊的排序方式,叫做自然排序。自然排序就是文档在磁盘上的顺序。
因为固定集合的文档总是按照插入的顺序存储的,自然顺序就是与此相同的。也可以使用自然顺序按照反向插入的顺序查询。
尾部游标
尾部游标是一种特殊的持久游标,这类游标不会在没有结果后销毁。游标受到tail -f
命令的启发,类似地会尽可能持续地获取结果。因为这类游标在没有结果后也不销毁,所以一旦有新文档添加到集合里面就会被取回并输出。尾部游标只能用在固定集合上。
可惜
Mongo shell
并不支持尾部游标。
游标没有销毁,要么处理结果,要么等着有更多的结果。
GridFS
:储存文件
GridFS
是一种在MongoDB
中存储大二进制文件的机制。使用GridFS
存储文件有以下几个原因:
-
利用
GridFS
可以简化需求。 -
GridFS
会直接利用已建立的复制或者分片机制,所以对于文件储存来说故障恢复和扩展都很容易。 -
GridFS
可以避免用于储存用户上传内容的文件系统出现的某些问题。 -
GridFS
不产生磁盘碎片,因为MongoDB
分配数据文件空间时以2GB
为一块。
内部原理
GridFS
是一个建立在普通MongoDB
文档基础上的轻量级文件储存规范。
GridFS
的一个基本思想就是可以将大文件分成很多块,每块作为一个单独的文档储存,这样就能存大文件了。由于MongoDB支持在文档中存储二进制数据,可以最大限度减少块的存储开销。另外,除了存储文件本身的块,还有一个单独的文档用来存储分块的信息和文件的元数据。
GridFS
的块有一个单独的集合。默认情况下,块将使用fs.chunks
集合,如有需要可以覆盖。
文件的元数据放在另一个集合中,默认是fs.files
。这里面的每个文档代表GridFS
中的一个文件,与文件相关的自定义元数据也可以存在其中,
服务器端脚本
在服务器端可以通过db.eval
函数来执行JavaSript
脚本。也可以把JavaScript脚本保存在数据库中,然后在别的数据库命令中调用。
db.eval
利用db.eval
可以在MongoDB的服务器端执行任意的JavaScript脚本。这个函数先将给定的JavaScript字符串传送给MongoDB(在这里执行),然后返回结果。
db.eval
可以用来模拟多文档事务:db.eval
锁住数据库,然后执行JavaScript,再解锁。虽然没有回滚机制,但这的确能保证一系列操作按照指定顺序发生(除非出错)。
发送代码有两个选择:或者封装进一个函数,或者不封装。
> db.eval("function() {return 1;}")
WARNING: db.eval is deprecated
1
> db.eval("function() {return 1;}")
WARNING: db.eval is deprecated
1
只有传递参数的时候,才必须要封装成一个函数。参数通过db.eval
的第二个参数传递。要写成一个数组的形式。
db.eval
的表达式要是复杂的话,调试起来就需要些技巧了。调试的一个好方法就是将调试信息写进数据库日志中,这个可以通过print
函数来完成。
存储JavaScript
每个MongoDB的数据库中都有个特殊的集合,叫做system.js
,用来存放JavaScript变量。这些变量可以在任何MongoDB的JavaScript上下文中调用,包括$where
子句,db.eval
调用,MapReduce
作业。用insert
就可以讲变量加进system.js
中。
使用存储的JavaScript缺点就是代码会与常规的袁大妈控制脱离,会搅乱客户端发送来的JavaScript。
最适合使用存储的JavaScript的情况就是程序中有多个地方都要用到一个JavaScript函数。将这样的函数放置在中心位置,要是有更新的话就可以不必每处都修改。
安全性
执行JavaScript代码,就必须要谨慎考虑MongoDB的安全性。使用不慎,就会发生类似于关系型数据库的注入式攻击。
数据库引用
数据库引用,也叫做DBRef
,DBRef
就行URL,唯一确定一个到文档的引用。它自动加载文档的 方式正如网站中URL通过连接自动加载Web页面一样。
什么是DBRef
DBRef
是一个内嵌文档,就像MongoDB的其他内嵌文档一样。但是DBRef
有一些必需键。
DBRef
指向一个集合,还有一个id_value
用来在集合里面根据_id
确定唯一的文档。这来那个IT哦啊信息使得DBRef
能唯一表示MongoDB数据库 内的任何一个文档。
DBRef
中的键的书序不能改变。第一个必须是$ref
,接着是$id
,然后是(可选的)$db
。