MongoDB 進階-關聯查詢

來源:互聯網
上載者:User

標籤:blog   http   io   os   使用   java   ar   for   檔案   

【蘇州需要工作的加我QQ,內推介紹費平分】MongoDB 進階

1.資料庫命令

a.命令的工作原理

drop命令,在shell中刪除一個集合,執行db.refactor.drop().其實這個函數實際啟動並執行是drop命令,

可以用runCommand來達到一樣的效果:

db.runCommand({"drop":"refactor"})

{         "nIndexesWas" : 1,         "msg" : "indexes dropped for collection",         "ns" : "test.refactor",         "ok" : 1 } 命令的響應是一個文檔,包含了命令是否執行成功,還可能有些其他的命令輸出的資訊.命令的響應文檔

都有一個"ok"鍵.ok鍵的值為1表示執行成功,為0表示執行失敗,當為0時,會有一個"errmsg"鍵,

它的值表示命令失敗的原因.

MongoDB中的命令其實是作為一種特殊類型的查詢實現的,這些查詢針對$cmd集合來執行.runCommand

僅僅是接受命令文檔,執行等價查詢,因此drop調用實際上是這樣的:

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

當MongoDB伺服器得到查詢$cmd集合的請求時,會啟動一套特殊的邏輯來處理,而不是交給普通的查詢代碼來執行.

幾乎所有MongoDB驅動程式都提供一個類似runCommand的協助方法來執行命令,如果有必要,也可以使用一個

簡單查詢的方式來運行命令.

訪問有些命令需要有管理員權限,必須在admin資料庫裡面運行.

 

b)要獲得所有命令的最新列表,可以在shell中運行db.listCommands(),

也可以使用http://localhost:28017/_commands

 

2.固定集合

MongoDB不僅支援普通集合,還支援 固定集合,固定集合要事先建立,而且大小固定.

固定集合像一個環形隊列,如果空間不足,最早的文檔就會被刪除,為新的文檔提供空間.

固定集合在新文檔插入的時候自動淘汰最早的文檔.

固定集合不能刪除文檔(自動淘汰文檔除外),更新(尺寸增大)將導致文檔移動.

固定集合中的文檔以插入的順序儲存,不用維護一個已刪除的文檔釋放空間列表.

固定集合預設情況下沒有索引,即便是"_id"上也沒有索引.

 

a.固定集合的屬性和用法

對固定集合插入的速度很快,做插入操作時,無需額外分配空間,伺服器也不必尋找空閑列表來放置文檔,

直接將文檔插入集合的末尾就行了,如果有必要就將舊的覆蓋.預設情況下插入也無需更新索引.

對固定集合按照插入順序輸出的查詢速度很快,以為文檔本身就是按照插入順序儲存的,按照這個

順序查詢就是遍曆一下,返回結果的順序就是文檔在磁碟上的順序.預設情況下,對固定集合進行尋找都

會以插入的順序返回結果.

固定集合能在新資料插入時,自動淘汰最早的資料.插入快速,按照插入順序查詢也很快,自動淘汰,這幾個

屬性群組合起來使得固定集合特別適合像日誌這種應用情境.事實上,MongoDB中設計固定集合的目的

就是用來儲存內部的複製日誌oplog.固定集合還有一個用法是緩衝少量的文檔,一般來說,固定集合

使用與任何想要自動淘汰到期屬性的情境.

b.建立固定集合

固定集合必須要在使用前顯示的建立.

如:

db.createCollection("refactorCapped",{"capped":true,size:100000,max:100})

上面的命令建立了一個固定集合refactorCapped,大小是100000位元組,最大的文檔數100.

當指定文檔數量的上限時,必須同時指定大小.淘汰機制只有在容量還沒有滿時才會依據文檔數量來工作.

要是容量滿了,淘汰機制則會依據容量來工作.

可以將普通集合轉化成固定集合,如將blog集合轉換成大小為10000位元組的固定集合

db.runCommand({convertToCapped:"blog",size:10000})

c.自然排序

固定集合的排序方式叫做自然排序.自然排序就是文檔在磁碟上的順序.

因為固定集合的文檔總是按照插入的順序儲存的,自然順序就是這樣的.預設情況下,

查詢固定集合後就是按照插入的順序返迴文檔.也可以使用自然排序按照反向插入的順序查詢

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

 

3.GridFS

GridFS是一種在MongoDB中儲存大二進位檔案的機制,使用GridFS存檔案的原因:

GridFS可以直接利用已經建立的複製或分區機制,對檔案儲存體來說故障恢複和擴充都很容易

GridFS可以避免用於儲存使用者上傳內容的檔案系統出現的某些問題,如GridFS在同一個目錄下放置大量的檔案是沒有問題的.

GridFS不產生磁碟片段,因為MongoDB分配資料檔案空間時以2GB為一塊.

a.使用GridFS

最簡單使用GridFS的方法是利用mongofiles.mongofiles可以用來在GridFS中上傳,下載,列示,尋找和刪除檔案.

可以用 mongofiles --help獲得協助

如:

b)內部原理

GridFS是一個建立在普通MongoDB文檔基礎上的輕量級檔案儲存體規範.MongoDB伺服器實際上對GridFS請求和普通的

請求一樣,所有相關工作都由用戶端驅動或者工具來完成.

GridFS的基本思想是可以將大檔案分成很多塊,每塊作為一個單獨的文檔儲存,這樣就能儲存大檔案了.由於MongoDB

支援在文檔中儲存位元據,可以最大限度減小塊的儲存開銷.另外,除了隱藏檔本身的快,還有一個單獨的文檔用來

儲存分塊的資訊和檔案的中繼資料.

GridFS的塊有個單獨的集合,預設情況下,塊將使用fs.chunks集合,如果需要可以覆蓋.這個塊集合裡面文檔的結構很簡單

{

  "_id":ObjectId("...."),

  "n":0,

  "data":BindData("..."),

  "files_id":ObjectId("....")

}

和別的MongoDB文檔一樣,塊也有自己唯一的"_id".files_id鍵是包含這個塊中繼資料的檔案文檔的"_id".

n表示塊編號,也就是這個塊在源檔案中的順序編號,data包含組成檔案塊的位元據.

檔案的中繼資料放在另一個集合中,預設是fs.files.這裡面的每個文檔代表GridFS中的一個檔案,與檔案相關的

自訂中繼資料也可以存在其中.除了使用者自訂的鍵,GridFS規範定義了一些鍵

_id

檔案唯一的id,在塊中作為files_id鍵的值儲存

length

檔案內容總的位元組數

chunksize

每塊的大小,以位元組為單位,預設是256k,必要時可以調整.

uploadDate

檔案存入GridFS的時間戳記

md5

檔案內容的md5檢驗和,由服務端用filemd5命令產生的,用於計算上傳塊的md5檢驗和

也意味著使用者可以檢驗md5鍵這個值,確保檔案正確上傳了.

db.fs.files.find()

 

4.伺服器端指令碼

在伺服器端可以通過db.eval函數來執行javascript指令碼,也可以把javascript指令碼儲存在資料庫中,然後

在別的資料庫命令中調用.

a.  db.eval

利用db.eval函數可以在MongoDB伺服器端執行javascript指令碼.這個函數先將給定的javascript字串傳遞給

MongoDB伺服器,在伺服器上執行,然後返回結果.

db.eval可以用來類比多文檔事務:db.eval鎖住資料庫,然後執行javascript,再解鎖.雖然沒有內建的復原機制,

但這能確保一系列操作按照指定的數序發生.

發送代碼有兩種方式,封裝一個函數或者不封裝,如:

db.eval("return ‘refactor‘;") db.eval("function(){return ‘refactor‘;}")

只有傳遞參數的時候,才必須要封裝成一個函數.參數通過db.eval的第二個參數傳遞,要寫成一個數組的形式.

如:

db.eval("function(name){return ‘hello,‘+name;}",[‘refactor‘])

若db.eval的運算式要是複雜的話,調試的辦法是將調試資訊寫進資料庫的日誌中

如:

db.eval("print(‘hello refactor‘)")

這樣在日誌裡就能找到hello refactor

 

b.儲存javascript

每個MongoDB的資料庫中都有個特殊的集合:system.js,用來存放javascript變數.這些變數可以在任何MongoDB的

javascript上下文中調用,包括"$where"子句,db.eval調用,MapReduce作業.用insert可以將變數存在system.js中

如:

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;")

 

system.js可以存放javascript代碼,這樣就可以很方便的自訂一些指令碼,如用javascript寫一個日誌函數,將其存放在

system.js中:

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

調用:

db.eval("log(‘refactor bolg test‘,1)")

使用儲存的javascript缺點是代碼會與常規的原始碼控制脫離,會弄亂用戶端發送來的javascript.

最適合使用儲存javascript的情況就是程式中有個地方都要用到一個javascript函數,這樣要是更新的話,

只需更新這個函數而不必沒出都修改.要是javascript代碼很長又要繁瑣使用的話,也可以使用儲存javascript,

這樣村一次會節省不少王擴傳輸時間.

 

c.安全性

執行javascript代碼就要考慮MongoDB的安全性.

如:

>func="function(){print(‘hello,"+username+"!‘);}"

如果username是使用者自訂的,可以使用這樣的字串"‘);db.dropDatabase();print(‘",

代碼就變成了這樣:

>func="function(){print(‘hello,‘);db.dropDatabase();print(‘!‘);}"

為了避免這種情況,要限定範圍.

絕大多數驅動程式都為傳遞給資料庫的代碼提供了一種特殊類型,這是因為代碼實際上可以看成是一個字串和一個

範圍的組合.範圍是一個儲存著變數名和值對應關係的文檔.當javascript函數執行的時候,這種映射就

構成了函數的局部範圍.

 

5.資料庫引用

DBRef就像url,唯一確定一個到文檔的引用.它自動載入文檔的方式就像網站中url通過連結自動載入web頁面一樣.

 

a.DBRef是什麼

DBRef是一個內嵌文檔,DBRef有些必選鍵,如:

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

DBRef指向一個集合,還有一個id_value用來在集合裡面根據"_id"確定唯一的文檔.這兩條資訊可以使DBRef能

唯一標識MongoDB資料庫內的任何一個文檔.如想引用另一個資料庫的文檔,DBRef中有可選鍵"$db"

{"$ref":collectionName,"$id":id_value,"$db":database}//注意鍵的順序不能改變.

 

b.執行個體

兩個集合 users(使用者),notes(筆記),

使用者可以建立筆記,筆記可以引用使用者或者別的筆記.

db.users.insert({"_id":"refactor","displayName":"dis_refactor"}) db.users.insert({"_id":"refactor2","displayName":"dis_refactor2"})

db.notes.insert({"_id":2,"author":"refactor","text":"refactor in mongodb"}) db.notes.insert( {   "_id":22,   "author":"refactor22",   "text":"...DBRef likes url",   "references":   [     {"$ref":"users","$id":"refactor"},     {"$ref":"notes","$id":2}   ] } )

var note=db.notes.findOne({"_id":22}); note.references.forEach(   function(ref){     printjson(db[ref.$ref].findOne({"_id":ref.$id}));   });

 

c.什麼時候使用DBRef

在MongoDB中表示這種對其他文檔的參考關聯性,並不是只有DBRef方式.

上面的例子就用了另外一種引用:每個note的author鍵僅儲存了author文檔的"_id"鍵,沒有必要用DBRef,因為已經

知道每個author就是users集合裡面的一個文檔.這種引用在GridFS的塊文檔中"files_id"鍵僅僅就是對文檔"_id"的引用.

在儲存引用的時候是選擇DBRef還是至儲存"_id"?

儲存"_id"會更加緊湊,對開發人員而言就很輕量.但是DBRef能夠引用任意集合(甚至是任意資料庫)的文檔,開發人員

不必知道和記住被引用的文檔在哪些集合裡面.驅動程式和一些工具對DBRef提供了額外的功能(如自動去引用).

總之,儲存一些對 不同 集合的 文檔的引用時,最好用DBRef.否則最好儲存"_id"作為引用來使用,這樣更簡單,也更容易操作.

 

MongoDB 進階-關聯查詢

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.