【譯】 MongoDB 入門教程
原文參見:http://www.mongodb.org/display/DOCS/Tutorial
譯文鏈接:http://chenxiaoyu.org/blog/archives/242
啟動數據庫
下載 MongoDB, 解壓后并啟動:
$ bin/mongod |
MongoDB 默認存儲數據目錄為 /data/db/ (或者 c:\data\db), 當然你也可以修改成不同目錄, 只需要指定 –dbpath 參數:
$ bin/mongod --dbpath /path/to/my/data/dir |
獲取數據庫連接
現在我們就可以使用自帶的shell工具來操作數據庫了. (我們也可以使用各種編程語言的驅動來使用MongoDB, 自帶的shell工具可以方便我們管理數據庫)
啟動 MongoDB JavaScript 工具:
$ bin/mongo |
默認 shell 連接的是本機localhost 上面的 test庫, 會看到:
MongoDB shell version: 0.9.8 url: test connecting to: test type "help" for help > |
“connecting to:” 這個會顯示你正在使用的數據庫的名稱. 想換數據庫的話可以:
> use mydb |
可以輸入 help 來查看所有的命令.
插入數據到集合
下面我們來建立一個test的集合并寫入一些數據. 建立兩個對象, j 和 t , 并保存到集合中去.
在例子里 ‘>’ 來表示是 shell 輸入提示
> j = { name : "mongo" }; {"name" : "mongo"} > t = { x : 3 }; { "x" : 3 } > db.things.save(j); > db.things.save(t); > db.things.find(); {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} {"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")} > |
有幾點需要注意下 :
- 不需要預先建立一個集合. 在第一次插入數據時候會自動建立.
- 在例子其實可以存儲任何結構的數據, 當然在實際應用我們存儲的還是相同元素的集合. 這個特性其實可以在應用里很靈活, 你不需要類似alter table 來修改你的數據結構
- 每次插入數據時候對象都會有一個ID, 名字叫 _id.
- 當你運行不同的例子, 你的對象ID值都是不同的.
下面再加點數據:
> for( var i = 1; i < 10; i++ ) db.things.save( { x:4, j:i } ); > db.things.find(); {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} {"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")} {"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} {"x" : 4 , "j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")} {"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} {"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} {"x" : 4 , "j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")} {"x" : 4 , "j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")} {"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} |
請注意下, 這里循環次數是10, 但是只顯示到8, 還有2條數據沒有顯示.
如果想繼續查詢下面的數據只需要使用 it 命令, 就會繼續下面的數據:
{"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} |
繼續
> it {"x" : 4 , "j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")} {"x" : 4 , "j" : 10 , "_id" : ObjectId("497cf87151712cf7758fbdc6")} |
從技術上講 find() 返回一個游標對象. 但在上面的例子里, 并沒有拿到一個游標的變量. 所以 shell 自動遍歷游標, 返回一個初始化的set, 并允許我們繼續用 it 迭代輸出.
當然我們也可以直接用游標來輸出, 不過這個是下一部分的內容了.
查詢數據
在沒有深入查詢之前, 我們先看看怎么從一個查詢中返回一個游標對象. 可以簡單的通過 find() 來查詢, 他返回一個任意結構的集合. 如果實現特定的查詢稍后講解.
實現上面同樣的查詢, 然后通過 while 來輸出:
> var cursor = db.things.find(); > while (cursor.hasNext()) { print(tojson(cursor.next())); } {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} {"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")} {"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} {"x" : 4 , "j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")} {"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} {"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} {"x" : 4 , "j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")} {"x" : 4 , "j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")} {"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} {"x" : 4 , "j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")} > |
上面的例子顯示了游標風格的迭代輸出. hasNext() 函數告訴我們是否還有數據, 如果有則可以調用 next() 函數. 這里我們也用了自帶的 tojson() 方法返回一個標準的 JSON 格式數據.
當我們使用的是 JavaScript shell, 可以用到JS的特性, forEach 就可以輸出游標了. 下面的例子就是使用 forEach() 來循環輸出:
forEach() 必須定義一個函數供每個游標元素調用.
> db.things.find().forEach( function(x) { print(tojson(x));}); {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} {"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")} {"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} {"x" : 4 , "j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")} {"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} {"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} {"x" : 4 , "j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")} {"x" : 4 , "j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")} {"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} {"x" : 4 , "j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")} > |
在 mongo shell 里, 我們也可以把游標當作數組來用 :
> var cursor = db.things.find(); > print (tojson(cursor[4])); {"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} |
使用游標時候請注意占用內存的問題, 特別是很大的游標對象, 有可能會內存溢出. 所以應該用迭代的方式來輸出.
下面的示例則是把游標轉換成真實的數組類型:
> var arr = db.things.find().toArray(); > arr[5]; {"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} |
請注意這些特性只是在 mongo shell 里使用, 而不是所有的其他應用程序驅動都支持.
MongoDB 游標對象不是沒有快照 – 如果有其他用戶在集合里第一次或者最后一次調用 next(), 你可以得不到游標里的數據. 所以要明確的鎖定你要查詢的游標.
指定條件的查詢
到這里我們已經知道怎么從游標里實現一個查詢并返回數據對象, 下面就來看看怎么根據指定的條件來查詢.
下面的示例就是說明如何執行一個類似SQL的查詢, 并演示了怎么在 MongoDB 里實現. 這是在 MongoDB shell 里查詢, 當然你也可以用其他的應用驅動或者語言來實現:
SELECT * FROM things WHERE name="mongo" |
>db.things.find({name:"mongo"}).forEach(function(x) { print(tojson(x));}); {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} >SELECT * FROM things WHERE x=4> db.things.find({x:4}).forEach(function(x) { print(tojson(x));}); {"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} {"x" : 4 , "j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")} {"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} {"x" : 4 , "j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} {"x" : 4 , "j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")} {"x" : 4 , "j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")} {"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} {"x" : 4 , "j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")} > |
查詢條件是 { a:A, b:B, … } 類似 “where a==A and b==B and …”, 更多的查詢方式可以參考 Mongo 開發教程部分.
上面顯示的是所有的元素, 當然我們也可以返回特定的元素, 類似于返回表里某字段的值, 只需要在 find({x:4}) 里指定元素的名字, 比如 j:
SELECT j FROM things WHERE x=4> db.things.find({x:4}, {j:true}).forEach(function(x) { print(tojson(x));}); {"j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} {"j" : 2 , "_id" : ObjectId("497cf87151712cf7758fbdbe")} {"j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")} {"j" : 4 , "_id" : ObjectId("497cf87151712cf7758fbdc0")} {"j" : 5 , "_id" : ObjectId("497cf87151712cf7758fbdc1")} {"j" : 6 , "_id" : ObjectId("497cf87151712cf7758fbdc2")} {"j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")} {"j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")} {"j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")} > |
請注意 “_id” 元素會一直被返回.
findOne() – 語法糖
為了方便, mongo shell (其他驅動) 避免游標的可能帶來的開銷, 提供一個findOne() 函數. 這個函數和 find() 參數一樣, 不過他返回游標里第一條數據, 或者返回 null 空數據庫.
作為一個例子, name==’mongo’ 可以用很多方法來實現, 可以用 next() 來循環游標(需要校驗是否為null), 或者當做數組返回第一個元素.
但是用 findOne() 方法則更簡單和高效:
> var mongo = db.things.findOne({name:"mongo"}); > print(tojson(mongo)); {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} > |
findOne 方法更跟 find({name:”mongo”}).limit(1) 一樣.
limit() 查詢
你可以需要限制結果集的長度, 可以調用 limit 方法.
這是強烈推薦高性能的原因, 通過限制條數來減少網絡傳輸, 例如:
> db.things.find().limit(3); in cursor for : DBQuery: example.things -> {"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")} {"x" : 3 , "_id" : ObjectId("497cf61651712cf7758fbdbc")} {"x" : 4 , "j" : 1 , "_id" : ObjectId("497cf87151712cf7758fbdbd")} > |
更多幫助
除非了一般的 help 之外, 你還可以查詢 help 數據庫和db.whatever 來查詢具體的說明.
如果你對一個函數要做什么, 你可以不輸入 {{()}} 這些結束的括號則可以輸出實現的源碼, 例如:
> db.foo.insert function (obj, _allow_dot) { if (!obj) { throw "no object passed to insert!"; } if (!_allow_dot) { this._validateForStorage(obj); } return this._mongo.insert(this._fullName, obj); } |
mongo 是一個完整的 JavaScript shell程序, 所以在 shell 里完全可以私用JS的方法、類、語法. 此外, MongoDB 定義 很多自己的類和全局變量 (比如 db). 這里可以查看完整的API說明 http://api.mongodb.org/js/.
接下來
看完這篇教程后下一步則看MongoDB更詳細的文檔 http://www.mongodb.org/display/DOCS/Manual