MongoDB权威指南读书笔记(一)

what is MongoDB ?

面向文档的数据库
  • 再也不有行的概念,再也不有预约义模式
  • 易于拓展
  • 丰富的功能javascript

    • 索引
    • 聚合
    • 特殊的集合类型
    • 文件存储
  • 高性能
  • 能够一个示实例拥有多个相互独立的数据库,每一个数据库拥有本身的集合

文档(document)

数据的基本单元,键值对的有序集
  • 文档格式:
    { "foo" : "3" }
  • 每一个文档都有一个特殊的键 "_id" ,这个键在文档中是惟一的
  • 文档的值能够是不一样的类型,使用相似 json 的语法来存储数据
  • 文档的键是字符串,除了少数状况,键可使用任意 UTF-8 字符
  • 键不能含有 \0(空字符),这个符号用来表示键的结尾
  • .$有特殊含义,只能在特定状况下使用
  • MongoDB不但区分·类别,并且区分大小写
  • 文档中不能有重复的键
  • 文档的键值对是有序的,但一般字段顺序·不重要

集合(collection)

一组文档的集合,能够看作有动态模式的表

动态模式

  • 具备动态的模式的集合中,文档能够是各式各样的
  • 例以下面两个文档能够存储在同一个集合里面:
    { "greeting" : "Hello, world" } , { "foo" : 5 }
  • 把同类型的文档放在一个集合里,数据会更加集中
  • 在集合中只放入一种类型的文档,能够更有效地对集合进行索引

命名

集合使用命名进行标识,集合名能够是如下任意UTF-8字符串
  • 集合名不能为空字符串""
  • 集合名不能包含字符\0,它表示集合名的结束
  • 集合名不能以stystem.开头,这是由于它是系统保留的前缀
  • 集合名不能包含$符号,由于系统生成的集合中包含$

子集合

使用.分隔命名空间的子集合,用来高效、简洁的组织数据java

数据库

MongoDB中,一个实例能够承载多个数据库,每一个数据库能够有零个或多个集合正则表达式

每一个数据库拥有独立权限,不一样的数据库存储在不一样的文件中mongodb

数据库名区分大小写,简单起见,数据库名所有小写,其它与集合命名方式相似shell

MongoDB的保留数据库名:数据库

  • admin
    用户权限,特定服务端命令
  • local
    不可复制,用于储存服务器本地集合
  • config
    用于分片设置

启动MongoDB

$ mongod --dbpath E:\mongodb\

终止 在shell中按下 Ctrl + Cjson

MongoDB shell

运行

$ mongo

链接其余计算机上的mongod实例

$ mongo host:30000/myDB

不链接到任何mongod实例

$ mongo --nodb
  • shell能够运行绝大多数的JavaScript程序
  • 多行输入时会进入未输入完成的状态,连续三次回车强制退出

MongoDB客户端

  • MongoDB shell是一个独立运行的MongoDB客户端
  • 启动时,shell链接到test数据库,并将数据库链接赋值给全局变量db

显示当前数据库

> db
test

显示全部数据库

> show databases

使用数据库user

> use user

shell的基本操做

建立

> post = {
    "content":"here is my blog",
    "date":new Date()
}

增长

> post = { "content":"here is my blog",  "date":new Date() }
> db.blog.insert(post)

查找

全部数组

> db.blog.find()

第一个安全

> db.blog.findOne()

更新

> db.blog.update({"content":"here is my blog"},"here")

删除

> db.blog.remove({"content":"here"})

基本数据结构

  • null
    null 用于表示空值或者不存在的字段
  • 布尔型
    布尔型有两个值true和false
  • 数值bash

    • shell默认使用64浮点数值
    • 整型数值可使用NumberInt()(4字节带符号整型)或者NumberLog()(8字节带符号整型)
  • 字符型
    UTF-8字符串
  • 日期
    新纪元以来的毫秒数,不存储时区
  • 正则表达式
    和JavaScript正则语法相同
  • 数组
  • 内嵌文档

    {"x":{"foo":"bar"}}
  • 对象id

    {"x":ObjectId()}
  • 二进制数据
  • 代码

    {"x":function(){}}

_id 和 ObjectId

_id

  • MongoDB文档必须有一个"_id"键,这个键能够是任意类型,默认是一个ObjectId对象
  • 每一个文档都有一个惟一的"_id"做为它的标识,同一个集合中的"_id"不能相同

ObjectId

  • 由24个16位进制数字组成的字符串
  • 前四位-时间戳 五到八-机器码 七和八位-进程标识符(PID) 九到十一-计数器

集合命名注意事项

  • db.version 是 db 的一个方法,用来返回当前服务器的版本
  • 访问version数据库必须使用db.getCollection("version");

可使用对象访问特殊命名集合或数据库

例如 db.blog[collection_name] db[db_name].find()

删除更新、和删除文档

插入新的文档

> db.foo.insertOne({"bar":"baz"})

这个操做会新建一个文档,自动新增"_id"键,而后保存到MongoDB中

批量插入

> db.foo.insert({"_id":1},{"_id":2},{"_id":3})

若是其中有一个文档插入失败,这个文档及其以后的全部文档失败,以前的文档依旧插入

批量文档

> db.foo.remove({})

option中能够传入条件,符合条件的数据将会被删除

删除集合

> db.foo.drop()

删除集合比删除全部文档的速度更快

文档替换

一个常见的问题:
查询条件匹配到了多个文档而后更新于第二个参数的存在就产生重复的_id值,数据库会抛出异常,全部文档都不会更新

正确的更新方法:

> db.people.update( { "_id" : ObjectId("4b3b9f67a1f631733d917a7c") } , joe )

使用文档修改器

  • $set修改器
设定一个键不存在就建立它,存在更新键对应的值,它还能够改变值的类型
  • $inc修改器
增长已有键的值,键不存在就建立一个

必须是数字类型,不能增长其它类型的值,修改其它类型请使用$set或者数值修改器

  • $unset修改器
删除一个键使用它
  • 数值修改器

    • $push已有数组末尾加入一个元素,没有就建立一个新数组
    • $slice的值必须是负数,它会限制数组最多有多少元素
    • $addToSet能够避免重复插入值
    • 删除数组中的元素
      特定元素

      > db.foo.insert({"arr":["a","b"]})
      > db.foo.update({},{"$pull":{"arr":"a"}})
    • $each批量更新数组

      > db.foo.update({"_id":ObjectId("5bf7f5ab1fcca531779d012d")},{"$push":{"hourly":{"$each":[5,2,3,4]}}}
  • 修改器速度

将文档插入数据库中时,依次插入的文档在磁盘上的位置是相邻的。
所以若是一个文档变大了,原来的位置放不下这个文档时,它会被移动到集合的另外一个位置。
当MongoDB不得不移动一个文档时,它会建立一个,它会修改集合的填充因子(padding factor)
填充因子: MongoDB为每一个新文档预留的增加位置

查看填充因子

> db.coll.stats()

注意:
删除、修改、增长都要使用$修改器,不然会将整个文档替换,例子:

> db.people.update( criteria , { "foo" : "bar" } )

这会使整个文档用{"foo":"bar"}替换

提升磁盘复用率

若是你的集合在进行插入和删除时会进行大量的移动或者是常常打乱数据,能够实用usePowerOf2Sizes选项提升磁盘复用率。

> db.runCommand({"collMod":collectionName,"usePowerOf2Sizes":true})

这个选项会致使以后全部的空间分配都是2的幂,使得空间分配再也不这么高效。

upsert

​ 若是没有找到找到符合条件的文档,就会以这个条件和更新文档为基础新建一个新的文档。若是找到了匹配的文档,则正常更新。没必要预置集合,同一个代码既能够建立文档又能够更新文档。

> db.foo.update({ "url" : "/blog"}, {"$inc" : { "pageviews" : 1 }}, true)

update的第三个参数就是个upsert

$setOnInsert

建立文档同时建立字段为它赋值,以后全部的更新操做这个字段的值再也不改变。

> db.foo.update({}, {"$setOnInsert" : { "createdAt" : new Date() }}, true)

​ 一般不须要保留createAt建立时间这样的字段,由于ObjectId中包含了建立时的时间戳,可是在预置或者初始化计数器时或者不使用ObjectId的集合来讲,$setOnInsert是很是有用的

save shell

​ 若文档不存在建立,存在更新。它只有一个参数:文档,若是包含_id键,save会调用upsert,不然会调用insert。使用它能够快速、方便的对文档进行更新。

> var x = db.foo.findOne()
> x.num = 42
> db.foo.save()

更新多个文档

​ 默认状况下,文档的更新只针对第一个匹配到的文档,多个条件符合时,其它文档不会改变。若想同时跟新多个文档能够将update的第四个参数设为true

> db.users.update({"birthday":"10/13/1988"},{"$set":{"gift":"Happy Brithday!"}}, false , true)

这样就给全部生日是1998年10月13的用户添加了礼物gift

若是想得到跟新了多少文档能够运行getLastError命令

> db.runCommand(getLastError:1)
{
    "err" : null,
    "updatedExisting" : true,
    "n" : 5,
    "ok" : true
}

返回被更新的文档

> db.runCommand("findAndModify ": "processes", "query" : {"status" : "READY"}, "sort":{"priority" : -1}, "update":{"$set" : "RUNNING"})
{
    "ok" : 1,
    "value" : {
       "_id" : ObjectId("4b3e7a18005cab32be6291f7"),
       "priority" : 1,
       "status" : "READY",
    }
}

返回的文档是更新前的值,但实际的文档依旧更新

写入安全机制

  • 应答式写入

数据库会给出响应,告诉你写入操做是否成功执行

  • 非应答式写入

不返回任何响应,没法得知写入是否成功

手动强制shell中进行检查,检查最后一次操做中的错误

> db.getLastError()

引用

[1] MongoDB权威指南

相关文章
相关标签/搜索