MongoDB入門串連資料庫
在這裡我們使用MongoDB提供的JavaScript shell進行資料庫操作,當然也可以通過不同的驅動利用其他程式設計語言實現同樣的功能,不過shell在管理資料庫的方面還是很方便的。
啟動JavaScript shell的方法很簡單,命令如下:
C:\mongodb\bin\mongo
在預設情況下,shell串連到本地test資料庫,可以看到如下資訊:
C:\mongodb\bin>mongo
MongoDB shell version: 2.0.2
connecting to: test
>
“connecting to”的後面是要串連的資料庫的名字,如果想換成其他的資料庫,可以用如下命令:
> use mydb
switched todbmydb
注意:切換資料庫後,如果切換的資料庫不存在,系統並不會馬上建立這個資料庫,而是在對它進行第一次插入操作時才建立。這意味著當你使用“show dbs”命令查看現有資料庫時,並不能看到切換的資料庫。
動態模式(無模式)
MongoDB包含資料庫(database)、集合(collection),以及和傳統關聯式資料庫很相似的索引結構(index)。對於資料庫和集合這些對象(object),系統會隱式地進行建立,然而一旦建立它們就被記錄到了系統目錄中(db.systems.collections,db.system.indexes)。
集合由文檔(document)組成,文檔中包含域(field),也就是傳統關聯式資料庫中的欄位。但與關聯式資料庫不同,MongoDB不會對域進行預定義,也沒有給文檔定義模式,這就意味著文檔中不同域和它們的值是可以變化的。因此,MongoDB並沒有“alter
table”操作來增加或者減少域的個數。在實際應用中,一個文檔中通常包含相同類型的結構,但這並不是必須的。這種彈性使得模式變動或者增加變得非常容易,幾乎不用寫任何指令碼程式就可實現“alter table”操作。另外,動態模式機制便於對基於MongoDB資料庫的軟體進行重複性開發,大大減少了由於模式變化所帶來的工作量。
向集合中插入資料
首先建立一個名為test的集合,再向test中插入資料。我們建立兩個對象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("4f361b1f64480e0bcb6d6021"),"name" : "mongo" }
{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),"x" : 3 }
>
注意:
我們並沒有預定義集合,資料庫是在進行第一次插入操作時自動建立集合的。
我們儲存的文檔包含不同的域,在這個例子中,文檔中沒有相同的資料元素。但在實際
應用中,往往把相同結構的資料存放區在一個集合中。
一旦被儲存到資料庫中,如果沒有事先定義,對象就會被自動分配一個ObjectId,並且
儲存到field_id域中。當你運行上面的例子時,會有不同的ObjectId。
向集合中增加更多的記錄,下面的代碼利用了迴圈結構:
> for (var i=1; i<=20; i++) db.things.save({x:4,j:i})
>db.things.find()
{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),"name" : "mongo" }
{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),"x" : 3 }
{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,"j" : 1 }
……
{ "_id" : ObjectId("4f36234964480e0bcb6d6034"), "x" : 4,"j" : 18 }
has more
>
值得注意的是,上面例子中沒有顯示出全部的文檔,shell預設顯示的數目是20。如果想查看其餘的文檔,可以使用it命令:
{ "_id" : ObjectId("4f36234964480e0bcb6d6034"), "x" : 4,"j" : 18 }
has more
>it
{ "_id" : ObjectId("4f36234964480e0bcb6d6035"), "x" : 4,"j" : 19 }
{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,"j" : 20 }
>
嚴格來講,find()返回的是指標對象。但是在上面的例子中,我們並沒有把指標對象賦予任何變數。所以,shell自動對指標進行迭代,直到給出初始的結果集,我們可以通過it命令顯示出其餘的資訊,但是也可以直接對find()返回的指標進行操作,11.3.3.4節中將對其進行介紹。
查詢資料
在討論資料查詢之前,先瞭解一下如何操作查詢結果,即指標對象。我們將使用簡單的find()方法,返回集合中全部的文檔,之後再討論如何寫出特定的查詢語句。
為了瞭解使用mongo shell時集合中的全部元素,我們需要明確地使用find()方法返回的指標。利用while迴圈對find()返回的指標進行迭代,實現和前面例子相同的查詢結果:
>var cursor=db.things.find()
>while (cursor.hasNext()) printjson(cursor.next())
{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),"name" : "mongo" }
{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),"x" : 3 }
{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,"j" : 1 }
……
{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,"j" : 20 }
>
上面的例子顯示了指標迭代器,hasNext()方法判斷是否還能返迴文檔,next()方法返回下一個文檔。我們也使用了內建的printjson()方法使文檔以JSON形式展現。
當在JavaScript shell下工作時,我們也可以利用JavaScript語言的特徵,比如使用forEach輸出指標對象。下面的代碼輸出與上面相同的查詢結果,但是在代碼中使用forEach而不是while迴圈:
>db.things.find().forEach(printjson)
{ "_id" : ObjectId("4f361b1f64480e0bcb6d6021"),"name" : "mongo" }
{ "_id" : ObjectId("4f361c6364480e0bcb6d6022"),"x" : 3 }
{ "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4,"j" : 1 }
……
{ "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4,"j" : 20 }
>
在使用forEach()方法的時候,必須為指標指向的每一個文檔定義函數(這裡用了內建方法printjson())。
在mongo shell中,可以像對數組一樣操作指標:
>var cursor=db.things.find()
>printjson(cursor[4])
{ "_id" : ObjectId("4f36234964480e0bcb6d6025"), "x" : 4,"j" : 3 }
>
當用這種方式使用指標時,指標指示的值都能同時載入到記憶體中,這一點不利於返回較大的查詢結果,因為有可能發生記憶體溢出。對於結果較大的查詢,應該用迭代方式輸出指標值。
另外,你可以將指標轉變為真正的數組進行處理:
>arr[5]
{ "_id" : ObjectId("4f36234964480e0bcb6d6026"), "x" : 4,"j" : 4 }
>
注意,這些數組特性都僅適用於shell模式,但對於其他語言環境並不適合。MongoDB指標並不是快照,當在集合上進行操作時,如果有其他人在集合裡第一次或者最後一次調用next(),那麼你的指標可能不能成功返回結果,所以要明確鎖定你要查詢的指標。
條件查詢
我們已經知道如何操作查詢返回的指標,現在我們要針對特定條件實現對查詢結果的篩選。一般來說,實現條件查詢就需要建立“查詢文檔”,即指明鍵需要匹配的模式和值的文檔。對於這一點用例子證明要比用文字解釋清楚得多。在下面的例子中,我們將給出SQL查詢,並且說明如何藉助mongoshell使得MongoDB能實現相同的查詢(參見表11-4與表11-5)。這種條件查詢是MongoDB的準系統,所以你也可以用其他程式驅動或者語言實現條件查詢。
表11-4 MongoDB條件查詢(name="mongo")
SELECT * FROM things WHERE name="mongo" |
>db.things.find({name:"mongo"}).forEach(printjson) { "_id" : ObjectId("4f361b1f64480e0bcb6d6021"), "name" : "mongo" } > |
表11-5 MongoDB條件查詢(x=4)
SELECT * FROM things WHERE x=4 |
>db.things.find({x:4}).forEach(printjson) { "_id" : ObjectId("4f36234964480e0bcb6d6023"), "x" : 4, "j" : 1 } { "_id" : ObjectId("4f36234964480e0bcb6d6024"), "x" : 4, "j" : 2 } |
續表
…… { "_id" : ObjectId("4f36234964480e0bcb6d6036"), "x" : 4, "j" : 20 } > |
查詢運算式本身是一個文檔,一個查詢文檔{a:A,b:B,…}意思是“where
a==A and b==B and …”。如果想瞭解更多條件查詢有關的資訊,可以到MongoDB官網上查看MongoDB開發人員手冊,網址如下:
http://www.mongodb.org/display/DOCS/Manual
MongoDB也允許返回“部分文檔”,也就是結果中只包含資料庫文檔的一些子項目,類似於關聯式資料庫中針對某些列的查詢。為了實現這個查詢,可以在find()方法中增加第二個參數,表示返回某些特定元素。為了便於說明,下面我們還是實現find({x:4})的查詢,只不過增加了額外的參數使得結果中只包含j元素:
表11-6 MongoDB條件查詢(返回特定元素j)
SELECT j FROM things WHERE x=4 |
>db.things.find({x:4},{j:true}).forEach(printjson) { "_id" : ObjectId("4f36234964480e0bcb6d6023"), "j" : 1 } …… { "_id" : ObjectId("4f36234964480e0bcb6d6036"), "j" : 20 } > |
注意:“_id”欄位總是會返回在結果中的。
作者簡介
陸嘉恒,中國人民大學教授,博士生導師。2006年畢業於新加坡國立大學電腦科學系,獲博士學位;2006-2008年在美國加利福尼亞大學爾灣分校(University of California, Irvine)進行博士後研究;2008年加入中國人民大學,2012年破格晉陞為教授。主要研究領域包括資料庫技術和雲端運算技術。先後在SIGMOD、VLDB、ICDE、WWW等國際重要會議和期刊上發表資料庫方向的論文40多篇,主編多本雲端運算和大資料的教材和著作。
本文節選自《大資料挑戰與NoSQL資料庫技術》一書。陸嘉恒編著,由電子工業出版社出版。