zoukankan      html  css  js  c++  java
  • MongoDB权威指南(6) Advanced Topics

    1.数据库命令

    mongoDB提供了范围广泛的数据库命令,覆盖了除create,read,update,delete之外的所有功能。比如我们前边用到的getLastError命令,用来查看update时受影响的数量。

    命令是如何工作的

    这里有个你比较熟悉的例子:drop,如果从shell里删除一个collection,我们运行db.test.drop().实际上,在内部执行的是drop命令,跟下边用runCommand执行的操作是一样的

    > db.runCommand({"drop" : "test"});
    {
    "nIndexesWas" : 1,
    "msg" : "indexes dropped for collection",
    "ns" : "test.test",
    "ok" : true
    }

    作为结果返回的document叫做命令响应,包括了一些信息,如命令执行是否成功等。

    实际上,mongoDB的命令被实现为一种对叫$cmd的collection的特殊查询,runCommand只是使用参数进行了一次查询,所以我们的drop也可以这样写

    db.$cmd.findOne({"drop" : "test"});

    当mongoDB服务器接到一个对$cmd的查询时,使用一种特殊的逻辑来处理。几乎所有的驱动都提供了runCommand方法来执行命令,实际上这些命令都可以通过执行查询的方式来完成。

    命令参考

    到目前mongoDB支持75个以上的数据库命令,而且这些命令越来越多,你可以通过两种方式查看支持的命令列表,一是在shell里执行db.listCommands(),二是在浏览器里访问mongoDB的管理站点http://localhost:28017/_commands

    下边列出了一些最常用的命令:

    • buildInfo: {"buildInfo" : 1}, 返回mongoDB服务器版本和宿主操作系统的信息
    • collStats: {"collStats" : collection},给出指定collection的统计信息,包括数据大小,分配的存储控件,索引大小等
    • distinct: {"distinct" : collection, "key": key, "query": query} 返回在指定的collection里符合query条件的所有key的值
    • drop: {"drop" : collection}, 删除collection的说有数据
    • dropDatabase: {"dropDatabase" : 1}, 删除当前数据库的所有数据
    • dropIndexes: {"dropIndexes" : collection, "index" : name}, 删除collection上名字为name的索引
    • findAndModify:参见第3章
    • getLastError:{"getLastError" : 1[, "w" : w[, "wtimeout" : timeout]]}, 检查此连接上最后操作的错误或状态信息,可以指定一个选项,此命令将会阻塞直到w个salves复制了最后的那个操作或者时间超时(毫秒)
    • isMaster: {"isMaster" : 1}, 检查此服务器是master还是slave
    • listCommands: {"listCommands" : 1}, 列出此服务器上所有可用命令
    • listDatabases: {"listDatabases" : 1},列出服务器上所有数据库
    • ping: {"ping" : 1},检查服务器是否正在运行,即使服务器处于锁定状体此命令也会立即返回
    • renameCollection: {"renameCollection" : a, "to" : b}, 将collection的名字从a改为b
    • repairDatabase:{"repairDatabase" : 1}, 修复并压缩当前数据库
    • serverStatus:{"serverStatus" : 1}, 获取此服务器的管理统计信息

    2.Capped Collections

    mongoDB还支持一种特殊的collection叫Capped Collections,这种collection是事先创建并且是大小固定的。固定大小就带来了一个问题,如果collection满了之后对其执行插入该如何处理。Capped Collection的工作方式像一个循环队列,如果空间用完了,那么最旧的数据会被删除掉,新数据会取代旧数据的位置。这就是说,随着新document的插入,最旧的document会自动消亡。

    某些操作在Capped Collection上是不允许执行的。不允许执行document删除,也不允许执行会导致document移动的更新(使document变大的更新),这样就可以保证Capped Collections里的document是按照插入顺序存储的。

    特性和用例

    Capped Collection的这些特点和限制会产生有趣的特性。首先是插入很快,执行插入的时候不再需要分配空间,服务器就不用查询空闲列表,插入的document直接放在collection的尾部。缺省情况下,也不会更新索引,所以一次插入本质上就是一次内存拷贝。另外一个特性是,按插入顺序查询很快,document是按照插入顺序存储的,只需要按它们在磁盘上的顺序遍历。最后,旧数据的自动消亡也是个有用的特性。包括了上述3个特性的Capped Collection对某些用例特别适用,如日志,实际上Capped Collection原本就是设计来存储内部复制日志的。另外还有个好的用例,缓存小规模的document。

    创建Capped Collections

    > db.createCollection("my_collection", {capped: true, size: 100000});
    { "ok" : true }

    另外还可以指定document的数量上限,如下

    > db.createCollection("my_collection", {capped: true, size: 100000, max: 100});
    { "ok" : true }

    将一个普通collection转化为Capped Collection

    > db.runCommand({convertToCapped: "test", size: 10000});
    { "ok" : true }

    自然排序

    自然排序是Capped Collection上的一种特殊排序,就是按照磁盘上的存储顺序排序。当然也可以按反存储顺序排序,指定参数-1.

    > db.my_collection.find().sort({"$natural" : -1})

    循环游标(Tailable Cursors)

    循环游标只能用于Capped Collection上,循环游标是一种特殊的持久性的游标,在结果集耗尽之后并不会关闭,当有了新document插入到collection之后,它可以继续取出。shell不支持循环游标。

    3.GridFS: 存储文件

    GridFS是mongoDB里的存储二进制大文件的机制。使用GridFS最简单的方式就是使用mongofiles工具,这个工具在分发包里边有。下边演示了如何使用mongofiles上传下载列出文件。

    $ echo "Hello, world" > foo.txt
    $ ./mongofiles put foo.txt
    connected to: 127.0.0.1
    added file: { _id: ObjectId('4c0d2a6c3052c25545139b88'),
    filename: "foo.txt", length: 13, chunkSize: 262144,
    uploadDate: new Date(1275931244818),
    md5: "a7966bf58e23583c9a5a4059383ff850" }
    done!
    $ ./mongofiles list
    connected to: 127.0.0.1
    foo.txt 13
    $ rm foo.txt
    $ ./mongofiles get foo.txt
    connected to: 127.0.0.1
    done write to: foo.txt
    $ cat foo.txt
    Hello, world

    ps:如果你使用的是windows控制台,需要把rm命令换成del,把cat命令换成type

    mongofiles还支持search和delete。

    GridFS是一个基于普通document之上的文件存储规范,mongoDB服务器对GridFS请求几乎没有做任何特殊处理,所有的工作都是客户端驱动和工具完成的。

    GridFS的基本思想是将大文件分割成多个块,每个块存储为一个document,除了存储文件的每个块外,还有个单独的document把这些块组织在一起,并且包含了文件的元数据信息。

    GridFS中的块有自己的collection,缺省是使用fs.chunks,文件元数据存储在另外一个collection,缺省为fs.files。

    4.服务器端脚本

    db.eval函数允许你在服务器端执行javascript代码,将javascript字符串传递给服务器,然后返回结果。

    db.eval可以用来模拟事务,db.eval会锁定数据库,执行javascript,然后解锁数据库。虽然没有回滚,这也能够让你保证一组操作是按顺序执行。

    代码可以包装进一个function发送也可以不包装,下边两行是等价的

    > db.eval("return 1;")
    1
    > db.eval("function() { return 1; }")
    1

    如果要传递参数的话,就必须将代码封装进函数了

    > db.eval("function(x,y,z) { return x + y + z; }", [num1, num2, num3])

    Stored Javascript

    mongoDB里的每个数据库都有个特殊的collection叫system.js,用于存储javascript变量,这些变量可以在任意的javascript上下文中使用,包括"$where"子句、db.eval调用、MapReduce任务等。通过简单的插入就可以添加javascript变量了。

    > db.system.js.insert({"_id" : "x", "value" : 1})
    > db.system.js.insert({"_id" : "y", "value" : 2})
    > db.system.js.insert({"_id" : "z", "value" : 3})

    这样就在全局范围定义了x、y、z三个变量,如果你想求它们的和

    > db.eval("return x+y+z;")
    6

    system.js同样可以存储javascript代码,例如,你想创建一个日志打印函数

    > db.system.js.insert({"_id" : "log", "value" :
    ... function(msg, level) {
    ...   var levels = ["DEBUG", "WARN", "ERROR", "FATAL"];
    ...   level = level ? level : 0; // check if level is defined
    ...   var now = new Date();
    ...   print(now + " " + levels[level] + msg);
    ... }})

    那么你就可以在任何javascript上下文中调用此函数了

    > db.eval("x = 1; log('x is '+x); x = 2; log('x is greater than 1', 1);");

    数据库日志中就会包含下边的内容

    Fri Jun 11 2010 11:12:39 GMT-0400 (EST) DEBUG x is 1
    Fri Jun 11 2010 11:12:40 GMT-0400 (EST) WARN x is greater than 1

    5.数据库引用(Database References/DBRef)

    一个DBRef就是一个嵌入的document,和其他的嵌入document一样,但是必须有一些特殊的key。如下

    {"$ref" : collection, "$id" : id_value}

    这个DBRef引用了collection和id_value,使用这两个值就可以唯一确定一个document。如果要引用其他数据库的document,还需要第三个key,即"$db"

    {"$ref" : collection, "$id" : id_value, "$db" : database}

    Note:DBRef里边的key的顺序是有影响的,第一个必须是"$ref",然后是"$id",然后是可选的"$db"。

    由于mongoDB是非关系型的(无join),document之间的引用(外键)通常是客户端通过额外的查询来完成的。mongoDB里有两种常用的做法,一是简单的手动引用,另外就是DBRef标准,很多驱动都是支持DBRef的。

    简单的手动引用

    一般来说,手动写代码来处理引用的办法用起来还是不错的,我们只需要把另外的document的_id的值存起来,然后进行查询,如:

    > // grab a random blog post:
    > p = db.postings.findOne();
    {
        "_id" : ObjectId("4b866f08234ae01d21d89604"),
        "author" : "jim",
        "title" : "Brewing Methods"
    }
    > // get more info on author of post p
    > a = db.users.findOne( { _id : p.author } )
    { "_id" : "jim", "email" : "jim@gmail.com" }
    
    > // inverse: given an author, find all blog posts for the author
    > db.postings.find( {author : a._id } )

    DBRef

    各个驱动对DBRef的实现不太一样,不是所有的驱动都把DBRef当成普通的嵌入document,有些提供了一个特殊类型来自动转换。C#中使用一个叫DBRef的类,构造函数有两个参数,collection的名字和_id,然后就可以用FollowReference方法来获取引用的document。

    在javascript(shell)中,如下例:

    > x = { name : 'Biology' }
    { "name" : "Biology" }
    > db.courses.save(x)
    > x
    { "name" : "Biology", "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
    > stu = { name : 'Joe', classes : [ new DBRef('courses', x._id) ] }
    // or we could write:
    // stu = { name : 'Joe', classes : [ {$ref:'courses',$id:x._id} ] }
    > db.students.save(stu)
    > stu
    {
            "name" : "Joe",
            "classes" : [
                    {
                            "$ref" : "courses",
                            "$id" : ObjectId("4b0552b0f0da7d1eb6f126a1")
                    }
            ],
            "_id" : ObjectId("4b0552e4f0da7d1eb6f126a2")
    }
    > stu.classes[0]
    { "$ref" : "courses", "$id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
    > stu.classes[0].fetch()
    { "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1"), "name" : "Biology" }
    >


  • 相关阅读:
    手机如何当电脑的摄像头使用
    内网穿透软件
    如何在laravel框架中使用阿里云的oss
    css position 定位详解
    laravel 速查表
    window10如何查看连接过的wifi密码
    sweetalert弹出层组件
    phpstudy安装 与phpstudy_Windows web面板安装
    程序员修炼之道读后感
    JAVA-WEB-简单的四则运算
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2458119.html
Copyright © 2011-2022 走看看