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權威指南

相關文章
相關標籤/搜索