1. 数据库命令
数据库级别的命令参数以键值对方式运行,如下所示:
1 >db.runCommand({“drop” : “test”})
其实上述数据库命令执行是作为一种特殊类型的查询来实现的,形式如下:
1 >db.$cmd.findOne({“drop” : “test”})
当MongoDB服务器得到查询$cmd集合的请求时,会启动一套特殊的逻辑来处理,而不是交给普通的查询代码来执行。
访问有些命令需要有管理员权限,必须在admin数据库里面运行。
2. 常用命令参数
(1) getLastError
1 {“getLastError” : 1}
查看对本集合执行的最后一次操作的错误信息或者其他状态信息。
(2) listCommands
1 {“listCommands” : 1}
返回所有可以在服务器上运行的命令及相关信息。
(3) listDatabases
1 {“listDatabase” : 1}
管理专用命令,列出服务器上所有的数据库。
(4) renameCollection
1 {“renameCollection” : a, “to” : b}
将集合a重命名为b,其中a和b都必须是完整的集合命名空间(例如“foo.bar”表示foo数据库中的bar集合)
(5) serverStatus
1 {“serverStatus” : 1}
返回这台服务器的管理统计信息。
3. 固定集合
固定集合,需要事先创建,而且大小固定。很像环形队列,如果空间不足,最早的文档就会被删除。
固定集合有几个特性:
(1) 对固定集合进行插入速度极快,因为插入时,无需额外分配空间,服务器也不必查找空闲列表来放置文档。
(2) 按照插入顺序输出的查询速度极快。
(3) 固定集合在新数据插入时,自动淘汰最早的数据。
创建固定集合的方式如下:
1 >db.createCollection(“my_collection”, {capped : true, size : 100000})
若指定了文档数量的上限,必须同时指定大小。如下:
1 >db.createCollection(“my_collection”, {capped : true, size : 100000, max : 100})
淘汰机制只有在容量还没有满时才会依据文档数量来工作。要是容量满了,淘汰机制则会依据容量来工作,就像别的固定集合一样。
固定集合有种特殊的排序方式,叫做自然排序。自然排序就是文档在磁盘上的顺序。可以使用自然排序按照反向插入的顺序查询。
1 >db.my_collection.find().sort({“$natural” : -1})
使用{“$natural” : 1}表示与默认顺序相同。
4. GridFS:存储文件
GridFS是一种在MongoDB中存储大二进制文件的机制。最简单的开始使用GridFS的方法就是利用mongofiles实用程序。
在操作系统的cmd命令行模式下,输入如下命令:
1 D:\> mongofiles put to foo.txt
表示将D盘根目录下的foo.txt文件添加到GridFS中。还有一个get操作是put的逆操作。如下:
1 D:\>mongofiles get foo.txt
表示将GridFS中的文件写入到D盘的根目录下。
同时基本的操作还包括list、search、delete等。
文件存储在GridFS中,其实是文件的元数据放在另一个集合中,默认是fs.files,这里面的每个文档代表GridFS中的一个文件。
5. 服务器端脚本
在服务器端可以通过db.eval函数来执行JavaScript脚本,也可以把JavaScript脚本保存在数据库中,然后在别的数据库命令中调用。
简单举例:
1 >db.eval(“return 1;”) 2 3 1 4 5 >db.eval(“function() {return 1;}”) 6 7 1
以上两种形式是等价的,db.eval函数先将给定的JavaScript字符串传送给MongoDB,然后返回结果。
只有传递参数的时候,才必须要封装成一个函数,参数通过db.eval的第二个参数传递,要写成一个数组的形式。例如:
1 >db.eval(“function(u) {print(‘Hello, ’ + u + ‘!’)}”, [username]);
注意:这里print出来的结果不会显示到命令行中,结果输出在日志文件中。
每个MongoDB的数据库中都有个特殊的集合——system.js,用来存放JavaScript变量。用insert就可以将变量加进system.js中。
1 >db.system.js.insert({“_id” : “x”, “value” : 1}) 2 3 >db.system.js.insert({“_id” : “y”, “value” : 2}) 4 5 >db.system.js.insert({“_id” : “z”, “value” : 3}) 6 7 >db.eval(“return x+y+z”) 8 9 6
执行JavaScript代码,就必须要谨慎考虑MongoDB的安全性,防止注入式攻击。
例如写如下的程序:
1 >func = “function() {print(‘Hello, “ + username + “!’);}”
如果username是用户自定义的,可能会是这样的字符串”’);db.dropDatabase();print(‘”,这样代码就成了下面这样:
1 >func = “function() {print(‘Hello, ‘); db.dropDatabase(); print(‘!’);}”
整个数据库被干掉了。
为了避免这种情况,要限定作用域,这里大家可以理解为服务器将传入的字符串参数仅当作字符串来处理,而不去解析字符串中包含的命令。在PHP中的写法如下:
$func = new MongoCode(“function() {print(‘Hello, “ + username + “!’);}”, array(“username” => $username));
数据库就会安全地输出如下字符串:
Hello, ‘); db.dropDatabase(); print(‘!
6. 数据库引用DBRef
DBRef在具体的应用中就是个内嵌文档,简单例子如下:
1 >func = “function() {print(‘Hello, ‘); db.dropDatabase(); print(‘!’);}”
DBRef指向一个集合,还有一个id_value用来在集合里面根据”_id”确定唯一的文档。这两条信息使得DBRef能唯一标识MongoDB数据库内的任何一个文档。若想引用另一个数据库中的文档,DBRef中有个可选键“$db”,如下:
1 {“$ref” : collection, “$id” : id_value, “$db” : database}
注意:DBRef中的键的顺序不能改变,第一个必须是“$ref”,接着是“$id”,然后是(可选的)“$db”。
例如notes集合中“_id”为20的文档中含有两个数据库引用内嵌文档。可以通过以下方式循环遍历每个数据库引用信息。
1 >var note = db.notes.findOne({“_id” : 20}) 2 3 >note.references.forEach(function(ref) { 4 5 … printjson(db[ref.$ref].findOne({“_id” : ref.$id})) 6 7 });
注意:这里的db[ref.$ref]相当于db.ref.$ref。