[MongoDB指導3]MongoDB基本操作教程

獲取數據庫

首先通過 快速上手 讓數據庫跑起來。

連接數據庫

現在我們通過數據庫的 shell 來實際操作一下。(注意:任何編程語言都可以通過合適的 驅動 進行類似的操作,只不過shell的方式更方便交互操作和管理。)

運行MongoDB JavaScript shell:

# 'mongo' 是shell執行文件。解壓目錄可能因安裝方法和平臺而不同。
$ bin/mongo

默認情況下shell將連接本機(localhost)的“test”數據庫。你將看到:

MongoDB shell version: 1.6.5
connecting to: test
>

“connecting to:” 表明shell連接的數據庫名。執行以下命令切換數據庫:

> use mydb
switched to db mydb

輸入 help 可以看到一個簡單的命令列表。

 給有其他數據庫經驗的開發者的提示

在下面的例子中你可能會注意到,我們沒有創建數據庫和聚集。MongoDB並不用那麼做。一旦你插入數據,MongoDB會建立對應的聚集和數據庫。要是查詢了不存在的聚集,Mongo就將其視爲空的聚集。

使用 use 命令來切換數據庫不會立即創建數據庫 - 數據庫會在首次插入數據時延遲創建。這意味着如果首次 use 一個數據庫,該數據庫不會在 show dbs 命令的列表裏顯示出來,直到插入數據。

向聚集中插入數據

讓我們創建一個測試聚集,然後插入一些數據。我們將會新建兩個對象 j  t , 然後將其存放在 things 聚集中。

下面的例子中,'>' 表示在shell命令提示符輸入的命令。

> j = { name : "mongo" };
{ "name" : "mongo" }
> t = { x : 3 };
{ "x" : 3 }
> db.things.save(j);
> db.things.save(t);
> db.things.find();
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
{ "_id" : ObjectId("4d0d9738e34d147e5f68c487"), "x" : 3 }
>

注意幾點:

  • 我們並沒有預先定義聚集。數據庫會在第一次插入操作時自動創建集。
  • 我們存儲的文檔可以擁有任意不同的“結構”。事實上在本例中,文檔之間根本沒有共同的數據元素。在實際應用中文檔通常都以相同的結構保存在聚集裏面。這種靈活意味着遷移或者擴展都非常容易。幾乎不需要寫腳本來執行諸如“alter table”之類的操作。
  • 一旦被插入數據庫,對象就被分配一個 [object ID](要是還沒有的話)存儲在 _id 域中
  • 你運行上面的例子時,你的ObjectID的值會有所不同。

下面再往聚集裏面添加一些記錄:

> for (var i = 1; i <= 20; i++) db.things.save({x : 4, j : i}); 
> db.things.find(); 
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
{ "_id" : ObjectId("4d0d9738e34d147e5f68c487"), "x" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c489"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48c"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48d"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48e"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48f"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c490"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c491"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c492"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c493"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c494"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c495"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c496"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c497"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "x" : 4, "j" : 18 }
has more

注意這裏並沒有列出所有的文檔 - shell 會默認顯示20個。先前已經有兩個文檔在聚集裏面了,所以這裏只能看見新插入的前18個文檔。

要是想接着看結果,可以用 it 命令。接着上面的例子往下:

{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "x" : 4, "j" : 18 }
has more
> it
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49a"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49b"), "x" : 4, "j" : 20 }

通常,find()會返回一個遊標對象,但是在上面那個例子中,我們並沒有將遊標賦值給一個變量。所以shell自動的移動遊標,並且把初始化後的結果返回給我們,同時允許我們通過 it 命令繼續移動遊標。

但是我們仍然可以直接使用遊標,在下一部分中將討論如何這樣做。

使用查詢訪問數據

在我們對查詢進行深入討論之前,我們先來看看如何通過一個遊標對象操作查詢結果。我們將使用簡單的find()查詢函數,它會返回一個聚集中的所有數據。隨後我們看看如何創建一些特定的查詢。

在使用 mongo shell 的時候,爲了查看所有聚集中的數據元素,我們需要顯式的使用從find()操作返回的遊標。

讓我們使用相同的查詢,但是這次我們使用find()返回的遊標,並且在while循環中移動遊標:

> var cursor = db.things.find();
> while (cursor.hasNext()) printjson(cursor.next());
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
{ "_id" : ObjectId("4d0d9738e34d147e5f68c487"), "x" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c489"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48c"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48d"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48e"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48f"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c490"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c491"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c492"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c493"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c494"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c495"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c496"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c497"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "x" : 4, "j" : 18 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49a"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49b"), "x" : 4, "j" : 20 }

上述例子展示了遊標的循環方式,hasNext()函數告知是否還有文檔返回,而next()函數則返回下一個文檔對象。同時我們還使用了內嵌的tojson()函數來把document的對象顯示成JSON數據格式。

當使用JavaScript shell 時,我們還可以享用其語言本身的函數式特性:可以對遊標調用 forEach 。還拿上面的例子來說,直接在遊標處將使用 forEach() 來代替while循環:

> db.things.find().forEach(printjson);
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
{ "_id" : ObjectId("4d0d9738e34d147e5f68c487"), "x" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c489"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48c"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48d"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48e"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48f"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c490"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c491"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c492"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c493"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c494"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c495"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c496"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c497"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "x" : 4, "j" : 18 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49a"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49b"), "x" : 4, "j" : 20 }

在{{forEach()}}裏必須定義一個函數來對遊標中的每個文檔進行操作。

 mongo shell 中,也可以把遊標當作數組處理:

> var cursor = db.things.find();
> printjson(cursor[4]);
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "x" : 4, "j" : 3 }

當這樣使用遊標時,注意這會將最大訪問數據(上面的例子中的cursor[4])以下的所有數據都同時加載到內存中。這對大結果集非常不合適,會導致內存不夠用的。當返回結果數量很大時,遊標應該作爲迭代器使用。

除了用數組的風格來操作遊標,也可以乾脆將遊標轉換程真正的數組:

> var arr = db.things.find().toArray();
> arr[5];
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "x" : 4, "j" : 4 }

請注意這種數組特性是[Mongo交互Shell]特有的,但並不是所有的驅動都支持。

MongoDB遊標並不做快照。如果在第一次到最後一次調用 next 之間,你或別人對數據進行了修改,那麼修改可能被返回,也可能不返回。要是想做快照查詢的話得使用顯式鎖。

定製查詢結果

現在我們知道了如何使用查詢返回的遊標對象,下面看看如何通過修改查詢來定製結果。

通常,可以通過創建一種鍵值相匹配的“查詢文檔”來實現定製查詢。

這些用實例更能說明問題。在下面的例子裏,我們將給出SQL查詢示例,並在MongDB的 mongo shell 中展示相同的查詢。這種指定的查詢對於MongoDB來說是基本方式,而且你也會在任何驅動和語言環境中找到類似的通用功能。

SELECT * FROM things WHERE name="mongo"
> db.things.find({name:"mongo"}).forEach(function(x) {print(tojson(x));});
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
SELECT * FROM things WHERE x=4
> db.things.find({x:4}).forEach(function(x) {print(tojson(x));});
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c489"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48c"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48d"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48e"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48f"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c490"), "x" : 4, "j" : 9 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c491"), "x" : 4, "j" : 10 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c492"), "x" : 4, "j" : 11 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c493"), "x" : 4, "j" : 12 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c494"), "x" : 4, "j" : 13 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c495"), "x" : 4, "j" : 14 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c496"), "x" : 4, "j" : 15 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c497"), "x" : 4, "j" : 16 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "x" : 4, "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "x" : 4, "j" : 18 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49a"), "x" : 4, "j" : 19 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49b"), "x" : 4, "j" : 20 }

查詢表達式本身就是一個文檔對象,如果是一個類似於{a:A, b:B, ...}的文檔查詢對象,則表示”where a==A and b==B and ...”。更多關於查詢的用法參考 Mongo開發者指南  [查詢與遊標] 章節。

MongoDB也允許返回”部分文檔”,也就是返回一個數據庫文檔的元素子集。您只要通過使用find()函數的第二個參數就可以做到這一點。
例如,我們在上面 find({x:4}) 的例子中,加一個參數來限制只返回j域的數據:

SELECT j FROM things WHERE x=4
> db.things.find({x:4}, {j:true}).forEach(printjson);
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "j" : 1 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c489"), "j" : 2 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48a"), "j" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48b"), "j" : 4 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48c"), "j" : 5 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48d"), "j" : 6 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48e"), "j" : 7 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c48f"), "j" : 8 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c490"), "j" : 9 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c491"), "j" : 10 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c492"), "j" : 11 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c493"), "j" : 12 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c494"), "j" : 13 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c495"), "j" : 14 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c496"), "j" : 15 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c497"), "j" : 16 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c498"), "j" : 17 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c499"), "j" : 18 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49a"), "j" : 19 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c49b"), "j" : 20 }

需要注意的是"_id"域是每次都要被返回的。

findOne() - 語法糖

爲了方便起見,mongo shell(和其他驅動)能避免讓你用編程來處理遊標,你只需要通過findOne()函數就能獲得一個文檔。findOne()和find()使用相同的參數,但是它不返回遊標,而是從數據庫中返回第一個文檔,或者沒有匹配條目時返回 null

例如,我們可以通過很多種方式檢索一個 name=='mongo' 的文檔,包括在遊標中調用next()函數(當然,要驗證完是否爲null 之後),或者把遊標看做一個數組然後訪問數組下標爲0的元素。

但是,findOne()函數是既方便又高效的:

> printjson(db.things.findOne({name:"mongo"}));
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }

由於只從數據庫返回一個對象,這種方式更加高效,而且在數據庫和網絡傳輸上做的工作更少。這種方式等價於find({name:"mongo"}).limit(1)。

使用 limit() 限制結果集

通過 limit() 方法可以指定返回結果的最大數量,這樣就能控制查詢結果的大小了。

強力推薦這種使用方式,它可以大大提高性能,因爲這樣減少了數據庫的工作量,也減少了網絡中的數據流量。舉個例子:

> db.things.find().limit(3);
{ "_id" : ObjectId("4d0d9727e34d147e5f68c486"), "name" : "mongo" }
{ "_id" : ObjectId("4d0d9738e34d147e5f68c487"), "x" : 3 }
{ "_id" : ObjectId("4d0d99ace34d147e5f68c488"), "x" : 4, "j" : 1 }

更多幫助

除了常用的 "help" 命令外,你還可以對 db 或者 db.whatever 調用 help 命令來查看可用方法概要。

如果你對某個方法做的事情好奇,你可以在輸入時不帶 (),然後shell會打印出該方法的源代碼,例如:

> printjson
function (x) {
    print(tojson(x));
}

mongo是一個完備的JavaScript shell,所以任何JavaScript方法,語法或類都可以在shell中使用。除此以外,MongoDB還定義一些自己的類和全局變量(如 db)。你可以查看完整的API文檔 http://api.mongodb.org/js/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章