mongoDB入门必读(概念与实战并重)
一、概述 MongoDB是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù)開(kāi)源項(xiàng)目。由C++語(yǔ)言編寫(xiě)。旨在為WEB應(yīng)用提供可護(hù)展的高性能數(shù)據(jù)存儲(chǔ)解決方案。
MongoDB是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫(kù)當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫(kù)的。他支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類(lèi)似json的bjson格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類(lèi)型。Mongo最大的特點(diǎn)是他支持的查詢(xún)語(yǔ)言非常強(qiáng)大,其語(yǔ)法有點(diǎn)類(lèi)似于面向?qū)ο蟮牟樵?xún)語(yǔ)言,幾乎可以實(shí)現(xiàn)類(lèi)似關(guān)系數(shù)據(jù)庫(kù)單表查詢(xún)的絕大部分功能,而且還支持對(duì)數(shù)據(jù)建立索引。?
Mongo主要解決的是海量數(shù)據(jù)的訪問(wèn)效率問(wèn)題,根據(jù)官方的文檔,當(dāng)數(shù)據(jù)量達(dá)到50GB以上的時(shí)候,Mongo的數(shù)據(jù)庫(kù)訪問(wèn)速度是MySQL的10倍以上。Mongo的并發(fā)讀寫(xiě)效率不是特別出色,根據(jù)官方提供的性能測(cè)試表明,大約每秒可以處理0.5萬(wàn)-1.5次讀寫(xiě)請(qǐng)求。
因?yàn)镸ongo主要是支持海量數(shù)據(jù)存儲(chǔ)的,所以Mongo還自帶了一個(gè)出色的分布式文件系統(tǒng)GridFS,可以支持海量的數(shù)據(jù)存儲(chǔ),但我也看到有些評(píng)論認(rèn)為GridFS性能不佳,有待驗(yàn)證。?
最后由于Mongo可以支持復(fù)雜的數(shù)據(jù)結(jié)構(gòu),而且?guī)в袕?qiáng)大的數(shù)據(jù)查詢(xún)功能,因此非常受到歡迎,很多項(xiàng)目都考慮用MongoDB來(lái)替代MySQL來(lái)實(shí)現(xiàn)不是特別復(fù)雜的Web應(yīng)用,比方說(shuō) why we migrated from MySQL to MongoDB就是一個(gè)真實(shí)的從MySQL遷移到MongoDB的案例,由于數(shù)據(jù)量實(shí)在太大,所以遷移到了Mongo上面,數(shù)據(jù)查詢(xún)的速度得到了非常顯著的提升。?
MongoDB也有一個(gè)ruby的項(xiàng)目 MongoMapper,是模仿Merb的DataMapper編寫(xiě)的MongoDB的接口,使用起來(lái)非常簡(jiǎn)單,幾乎和DataMapper一模一樣,功能非常強(qiáng)大易用。?
總結(jié)起來(lái),monggDB的特點(diǎn)是高性能、易部署、易使用,存儲(chǔ)數(shù)據(jù)非常方便。主要功能特性有:
*面向集合存儲(chǔ),易存儲(chǔ)對(duì)象類(lèi)型的數(shù)據(jù)。
*模式自由。
*支持動(dòng)態(tài)查詢(xún)。
*支持完全索引,包含內(nèi)部對(duì)象。
*支持查詢(xún)。
*支持復(fù)制和故障恢復(fù)。
*使用高效的二進(jìn)制數(shù)據(jù)存儲(chǔ),包括大型對(duì)象(如視頻等)。
*自動(dòng)處理碎片,以支持云計(jì)算層次的擴(kuò)展性
*支持RUBY,PYTHON,JAVA,C++,PHP等多種語(yǔ)言。
*文件存儲(chǔ)格式為BSON(一種JSON的擴(kuò)展)
*可通過(guò)網(wǎng)絡(luò)訪問(wèn)
所謂“面向集合”(Collenction-Orented),意思是數(shù)據(jù)被分組存儲(chǔ)在數(shù)據(jù)集中,被稱(chēng)為一個(gè)集合(Collenction)。每個(gè)集合在數(shù)據(jù)庫(kù)中都有一個(gè)唯一的標(biāo)識(shí)名,并且可以包含無(wú)限數(shù)目的文檔。集合的概念類(lèi)似關(guān)系型數(shù)據(jù)庫(kù)(RDBMS)里的表(table),不同的是它不需要定義任何模式(schema)。
模式自由(schema-free),意味著對(duì)于存儲(chǔ)在mongodb數(shù)據(jù)庫(kù)中的文件,我們不需要知道它的任何結(jié)構(gòu)定義。如果需要的話,你完全可以把不同結(jié)構(gòu)的文件存儲(chǔ)在同一個(gè)數(shù)據(jù)庫(kù)里。
存儲(chǔ)在集合中的文檔,被存儲(chǔ)為鍵-值對(duì)的形式。鍵用于唯一標(biāo)識(shí)一個(gè)文檔,為字符串類(lèi)型,而值則可以是各中復(fù)雜的文件類(lèi)型。我們稱(chēng)這種存儲(chǔ)形式為BSON(Binary Serialized dOcument Format)。
MongoDB的優(yōu)點(diǎn)
- 高性能,速度非常快(如果你的內(nèi)存足夠的話)
- 沒(méi)有固定的表結(jié)構(gòu),不用為了修改表結(jié)構(gòu)而進(jìn)行數(shù)據(jù)遷移
- 查詢(xún)語(yǔ)言簡(jiǎn)單,容易上手
- 使用Sharding實(shí)現(xiàn)水平擴(kuò)展
- 部署方便
使用MongoDB,你得記住以下幾點(diǎn):
- MongoDB 假設(shè)你有大磁盤(pán)空間
- MongoDB 假設(shè)你的內(nèi)存也足夠大于放下你的熱數(shù)據(jù)
- MongoDB 假設(shè)你是部署在64位系統(tǒng)上的(32位有2G的限制,試用還可以)
- MongoDB 假設(shè)你的系統(tǒng)是little-endian的
- MongoDB 假設(shè)你有多臺(tái)機(jī)器(并不專(zhuān)注于單機(jī)可靠性)
- MongoDB 假設(shè)你希望用安全換性能,同時(shí)允許你用性能換安全
MongoDB在下面領(lǐng)域不太擅長(zhǎng)
- 不太穩(wěn)定,特別是auto-sharding目前還有很多問(wèn)題
- 不支持SQL,這意味著你很多通過(guò)SQL接口的工具不再適用
- 持久化,MongoDB單機(jī)可靠性不太好,宕機(jī)可能丟失一段時(shí)間的數(shù)據(jù)
- 相關(guān)文檔比較少,新功能都有這個(gè)問(wèn)題
- 相關(guān)人才比較難找,這也是新功能的問(wèn)題之一?
二、安裝
MongoDB服務(wù)端可運(yùn)行在Linux、Windows或OS X平臺(tái),支持32位和64位應(yīng)用,默認(rèn)端口為27017。推薦運(yùn)行在64位平臺(tái),因?yàn)镸ongoDB
在32位模式運(yùn)行時(shí)支持的最大文件尺寸為2GB。MongoDB把數(shù)據(jù)存儲(chǔ)在文件中(默認(rèn)路徑為:/data/db),為提高效率使用內(nèi)存映射文件進(jìn)行管理。
(一)Linux/OS X下:
1 建立數(shù)據(jù)目錄
mkdir -p /data/db
2 下載壓縮包
curl -O?http://downloads.mongodb.org/linux/mongodb-linux-i686-latest.tgz
3 解壓縮文件
tar xzf mongodb-linux-i386-latest.tgz
4 啟動(dòng)服務(wù)
bin/mongod run &
5 使用自帶客戶(hù)端連接
/bin/mongo
6 測(cè)試
db.foo.save( { a : 1 } )
db.foo.findOne()
(二)windows下:
1 建立數(shù)據(jù)目錄c:\data\db
2 下載壓縮包,解壓文件
3 啟動(dòng)服務(wù)
bin\mongod.exe run
4 自帶客戶(hù)端
bin\mongon.exe
在LINUX和WINDOWS系統(tǒng)下的使用大同小異,不同的地方主要是默認(rèn)的數(shù)據(jù)存儲(chǔ)目錄。LINUX類(lèi)系統(tǒng)下存放在/data/db下,而WINDOWS
會(huì)存放在C:\data\db下。可以在啟動(dòng)時(shí)使用--dbpath參數(shù)指定存儲(chǔ)目錄并啟動(dòng)。如:bin\mongod.exe --dbpath d:\data\mongo
常用啟動(dòng)參數(shù):
run 直接啟動(dòng)。例:./mongod run
--dbpath 指定特定存儲(chǔ)目錄啟動(dòng),若目錄不存在則創(chuàng)建。例:./mongod --dbpath /var/data/mongo
--port 指定端口啟動(dòng)。例:./mongod --port 12345
停止MONGO服務(wù):
方法1:服務(wù)端停止,可使用Ctrl+C
方法2:在客戶(hù)端停止,可先連接客戶(hù)端
./mongo
并使用命令
db.shutdownerver()
然后退出客戶(hù)端
exit
三、mongoDB常用命令
1、與Mql對(duì)照
?
| MySQL | MongoDB | 說(shuō)明 |
| mysqld | mongod | 服務(wù)器守護(hù)進(jìn)程 |
| mysql | mongo | 客戶(hù)端工具 |
| mysqldump | mongodump | 邏輯備份工具 |
| mysql | mongorestore | 邏輯恢復(fù)工具 |
| ? | db.repairDatabase() | 修復(fù)數(shù)據(jù)庫(kù) |
| mysqldump | mongoexport | 數(shù)據(jù)導(dǎo)出工具 |
| source | mongoimport | 數(shù)據(jù)導(dǎo)入工具 |
| grant * privileges on *.* to … | Db.addUser() Db.auth() | 新建用戶(hù)并權(quán)限 |
| show databases | show dbs | 顯示庫(kù)列表 |
| Show tables | Show collections | 顯示表列表 |
| Show slave status | Rs.status | 查詢(xún)主從狀態(tài) |
| Create table users(a int, b int) | db.createCollection("mycoll", {capped:true, size:100000})?另:可隱式創(chuàng)建表。 | 創(chuàng)建表 |
| Create INDEX idxname ON users(name) | db.users.ensureIndex({name:1}) | 創(chuàng)建索引 |
| Create INDEX idxname ON users(name,ts DESC) | db.users.ensureIndex({name:1,ts:-1}) | 創(chuàng)建索引 |
| Insert into users values(1, 1) | db.users.insert({a:1, b:1}) | 插入記錄 |
| Select a, b from users | db.users.find({},{a:1, b:1}) | 查詢(xún)表 |
| Select * from users | db.users.find() | 查詢(xún)表 |
| Select * from users where age=33 | db.users.find({age:33}) | 條件查詢(xún) |
| Select a, b from users where age=33 | db.users.find({age:33},{a:1, b:1}) | 條件查詢(xún) |
| select * from users where age<33 | db.users.find({'age':{$lt:33}}) | 條件查詢(xún) |
| select * from users where age>33 and age<=40 | db.users.find({'age':{$gt:33,$lte:40}}) | 條件查詢(xún) |
| select * from users where a=1 and b='q' | db.users.find({a:1,b:'q'}) | 條件查詢(xún) |
| select * from users where a=1 or b=2 | db.users.find( { $or : [ { a : 1 } , { b : 2 } ] } ) | 條件查詢(xún) |
| select * from users limit 1 | db.users.findOne() | 條件查詢(xún) |
| select * from users where name like "%Joe%" | db.users.find({name:/Joe/}) | 模糊查詢(xún) |
| select * from users where name like "Joe%" | db.users.find({name:/^Joe/}) | 模糊查詢(xún) |
| select count(1) from users | Db.users.count() | 獲取表記錄數(shù) |
| select count(1) from users where age>30 | db.users.find({age: {'$gt': 30}}).count() | 獲取表記錄數(shù) |
| select DISTINCT last_name from users | db.users.distinct('last_name') | 去掉重復(fù)值 |
| select * from users ORDER BY name | db.users.find().sort({name:-1}) | 排序 |
| select * from users ORDER BY name DESC | db.users.find().sort({name:-1}) | 排序 |
| EXPLAIN select * from users where z=3 | db.users.find({z:3}).explain() | 獲取存儲(chǔ)路徑 |
| update users set a=1 where b='q' | db.users.update({b:'q'}, {$set:{a:1}}, false, true) | 更新記錄 |
| update users set a=a+2 where b='q' | db.users.update({b:'q'}, {$inc:{a:2}}, false, true) | 更新記錄 |
| delete from users where z="abc" | db.users.remove({z:'abc'}) | 刪除記錄 |
| ? | db. users.remove() | 刪除所有的記錄 |
| drop database IF EXISTS test; | use test db.dropDatabase() | 刪除數(shù)據(jù)庫(kù) |
| drop table IF EXISTS test; | db.mytable.drop() | 刪除表/collection |
| ? | db.addUser(‘test’, ’test’) | 添加用戶(hù) readOnly-->false |
| ? | db.addUser(‘test’, ’test’, true) | 添加用戶(hù) readOnly-->true |
| ? | db.addUser("test","test222") | 更改密碼 |
| ? | db.system.users.remove({user:"test"}) 或者db.removeUser('test') | 刪除用戶(hù) |
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | use admin | 超級(jí)用戶(hù) |
| ? | db.auth(‘test’, ‘test’) | 用戶(hù)授權(quán) |
| ? | db.system.users.find() | 查看用戶(hù)列表 |
| ? | show users | 查看所有用戶(hù) |
| ? | db.printCollectionStats() | 查看各collection的狀態(tài) |
| ? | db.printReplicationInfo() | 查看主從復(fù)制狀態(tài) |
| ? | show profile | 查看profiling |
| ? | db.copyDatabase('mail_addr','mail_addr_tmp') | 拷貝數(shù)據(jù)庫(kù) |
| ? | db.users.dataSize() | 查看collection數(shù)據(jù)的大小 |
| ? | db. users.totalIndexSize() | 查詢(xún)索引的大小 |
?
2、shell數(shù)據(jù)操作實(shí)戰(zhàn)?
插入數(shù)據(jù)到集合
下面我們來(lái)建立一個(gè)test的集合并寫(xiě)入一些數(shù)據(jù). 建立兩個(gè)對(duì)象, j 和 t , 并保存到集合中去.
在例子里 ‘>’ 來(lái)表示是 shell 輸入提示符
有幾點(diǎn)需要注意下 :
- 不需要預(yù)先建立一個(gè)集合. 在第一次插入數(shù)據(jù)時(shí)候會(huì)自動(dòng)建立.
- 在例子其實(shí)可以存儲(chǔ)任何結(jié)構(gòu)的數(shù)據(jù), 當(dāng)然在實(shí)際應(yīng)用我們存儲(chǔ)的還是相同元素的集合. 這個(gè)特性其實(shí)可以在應(yīng)用里很靈活, 你不需要類(lèi)似alter table 來(lái)修改你的數(shù)據(jù)結(jié)構(gòu)
- 每次插入數(shù)據(jù)時(shí)候?qū)ο蠖紩?huì)有一個(gè)ID, 名字叫 _id.
- 當(dāng)你運(yùn)行不同的例子, 你的對(duì)象ID值都是不同的.
下面再加點(diǎn)數(shù)據(jù):
> 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")}請(qǐng)注意下, 這里循環(huán)次數(shù)是10, 但是只顯示到8, 還有2條數(shù)據(jù)沒(méi)有顯示.
如果想繼續(xù)查詢(xún)下面的數(shù)據(jù)只需要使用 it 命令, 就會(huì)繼續(xù)下面的數(shù)據(jù):
{"x" : 4 , "j" : 7 , "_id" : ObjectId("497cf87151712cf7758fbdc3")}{"x" : 4 , "j" : 8 , "_id" : ObjectId("497cf87151712cf7758fbdc4")}繼續(xù)
> it{"x" : 4 , "j" : 9 , "_id" : ObjectId("497cf87151712cf7758fbdc5")}{"x" : 4 , "j" : 10 , "_id" : ObjectId("497cf87151712cf7758fbdc6")}從技術(shù)上講 find() 返回一個(gè)游標(biāo)對(duì)象. 但在上面的例子里, 并沒(méi)有拿到一個(gè)游標(biāo)的變量. 所以 shell 自動(dòng)遍歷游標(biāo), 返回一個(gè)初始化的set, 并允許我們繼續(xù)用 it 迭代輸出.
當(dāng)然我們也可以直接用游標(biāo)來(lái)輸出, 不過(guò)這個(gè)是下一部分的內(nèi)容了.
查詢(xún)數(shù)據(jù)
在沒(méi)有深入查詢(xún)之前, 我們先看看怎么從一個(gè)查詢(xún)中返回一個(gè)游標(biāo)對(duì)象. 可以簡(jiǎn)單的通過(guò) find() 來(lái)查詢(xún), 他返回一個(gè)任意結(jié)構(gòu)的集合. 如果實(shí)現(xiàn)特定的查詢(xún)稍后講解.
實(shí)現(xiàn)上面同樣的查詢(xún), 然后通過(guò) while 來(lái)輸出:
上面的例子顯示了游標(biāo)風(fēng)格的迭代輸出. hasNext() 函數(shù)告訴我們是否還有數(shù)據(jù), 如果有則可以調(diào)用 next() 函數(shù). 這里我們也用了自帶的 tojson() 方法返回一個(gè)標(biāo)準(zhǔn)的 JSON 格式數(shù)據(jù).
當(dāng)我們使用的是 JavaScript shell, 可以用到JS的特性, forEach 就可以輸出游標(biāo)了. 下面的例子就是使用 forEach() 來(lái)循環(huán)輸出:
forEach() 必須定義一個(gè)函數(shù)供每個(gè)游標(biāo)元素調(diào)用.
> 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 里, 我們也可以把游標(biāo)當(dāng)作數(shù)組來(lái)用 :
> var cursor = db.things.find();> print (tojson(cursor[4]));{"x" : 4 , "j" : 3 , "_id" : ObjectId("497cf87151712cf7758fbdbf")}使用游標(biāo)時(shí)候請(qǐng)注意占用內(nèi)存的問(wèn)題, 特別是很大的游標(biāo)對(duì)象, 有可能會(huì)內(nèi)存溢出. 所以應(yīng)該用迭代的方式來(lái)輸出.
下面的示例則是把游標(biāo)轉(zhuǎn)換成真實(shí)的數(shù)組類(lèi)型:
請(qǐng)注意這些特性只是在 mongo shell 里使用, 而不是所有的其他應(yīng)用程序驅(qū)動(dòng)都支持.
MongoDB 游標(biāo)對(duì)象不是沒(méi)有快照 – 如果有其他用戶(hù)在集合里第一次或者最后一次調(diào)用 next(), 你可以得不到游標(biāo)里的數(shù)據(jù). 所以要明確的鎖定你要查詢(xún)的游標(biāo).
指定條件的查詢(xún)
到這里我們已經(jīng)知道怎么從游標(biāo)里實(shí)現(xiàn)一個(gè)查詢(xún)并返回?cái)?shù)據(jù)對(duì)象, 下面就來(lái)看看怎么根據(jù)指定的條件來(lái)查詢(xún).
下面的示例就是說(shuō)明如何執(zhí)行一個(gè)類(lèi)似SQL的查詢(xún), 并演示了怎么在 MongoDB 里實(shí)現(xiàn). 這是在 MongoDB shell 里查詢(xún), 當(dāng)然你也可以用其他的應(yīng)用驅(qū)動(dòng)或者語(yǔ)言來(lái)實(shí)現(xiàn):
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")}>查詢(xún)條件是 { a:A, b:B, … } 類(lèi)似 “where a==A and b==B and …”, 更多的查詢(xún)方式可以參考 Mongo 開(kāi)發(fā)教程部分.
上面顯示的是所有的元素, 當(dāng)然我們也可以返回特定的元素, 類(lèi)似于返回表里某字段的值, 只需要在 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")}>請(qǐng)注意 “_id” 元素會(huì)一直被返回.
findOne()?
為了方便, mongo shell (其他驅(qū)動(dòng)) 避免游標(biāo)的可能帶來(lái)的開(kāi)銷(xiāo), 提供一個(gè)findOne() 函數(shù). 這個(gè)函數(shù)和 find() 參數(shù)一樣, 不過(guò)他返回游標(biāo)里第一條數(shù)據(jù), 或者返回 null 空數(shù)據(jù)庫(kù).
作為一個(gè)例子, name==’mongo’ 可以用很多方法來(lái)實(shí)現(xiàn), 可以用 next() 來(lái)循環(huán)游標(biāo)(需要校驗(yàn)是否為null), 或者當(dāng)做數(shù)組返回第一個(gè)元素.
但是用 findOne() 方法則更簡(jiǎn)單和高效:
> var mongo = db.things.findOne({name:"mongo"});> print(tojson(mongo));{"name" : "mongo" , "_id" : ObjectId("497cf60751712cf7758fbdbb")}>findOne 方法更跟 find({name:”mongo”}).limit(1) 一樣.
limit() 查詢(xún)
你可以需要限制結(jié)果集的長(zhǎng)度, 可以調(diào)用 limit 方法.
這是強(qiáng)烈推薦高性能的原因, 通過(guò)限制條數(shù)來(lái)減少網(wǎng)絡(luò)傳輸, 例如:
> 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 之外, 你還可以查詢(xún) help 數(shù)據(jù)庫(kù)和db.whatever 來(lái)查詢(xún)具體的說(shuō)明.
這篇寫(xiě)得常用命令也不錯(cuò)http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html
四、與java結(jié)合
使用JAVA語(yǔ)言操作MONGODB非常簡(jiǎn)單,只要將驅(qū)動(dòng)文件加入到CLASSPATH中就可以使用。
junit-4.11和hamcrest-core-1.3是junit4依賴(lài)包
mongo-java-driver-2.9.3為mongodb的java驅(qū)動(dòng)包
實(shí)戰(zhàn):
import com.mongodb.Mongo;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.MongoAdmin;
1、獲得連接
Mongo db = new Mongo("mydb");
Mongo db = new Mongo("localhost", "mydb");
Mongo db = new Mongo("localhost", 27017, "mydb");
查看mongoDB數(shù)據(jù)庫(kù)列表?
Mongo m = new Mongo();?
for (String s : m.getDatabaseNames()) {?
System.out.println(s);?
}?
刪除一個(gè)數(shù)據(jù)庫(kù)?
Mongo m = new Mongo();?
m.dropDatabase("myDatabaseName");?
2 安全驗(yàn)證(非必選)
MongoDB服務(wù)可以在安全模式運(yùn)行,此時(shí)任何客戶(hù)端要連接數(shù)據(jù)庫(kù)時(shí)需使用用戶(hù)名和密碼。在JAVA中可使用如下方法連接:
boolean auth = db.authenticate(userName, password);
如果用戶(hù)名密碼驗(yàn)證通過(guò),返回值為true,否則為false
3 獲取集合列表
每個(gè)數(shù)據(jù)庫(kù)都存在零個(gè)或多個(gè)集合,需要時(shí)你可以獲得他們的列表:
Set<String> colls = db.getCollectionNames();
for(String s : colls){
System.out.println(s);
}
4 獲得一個(gè)集合
要獲得某個(gè)特定集合,你可以指定集合的名字,并使用getCollection()方法:
DBCollection coll = db.getCollection("testCollection");
當(dāng)你獲取了這個(gè)集合對(duì)象,你就可以對(duì)數(shù)據(jù)進(jìn)行增刪查改之類(lèi)的操作。
查看一個(gè)集合的索引?
List<DBObject> list = coll.getIndexInfo();?
for (DBObject o : list) {?
System.out.println(o);?
}?
5 插入文檔
默認(rèn)ID?
當(dāng)保存的對(duì)象沒(méi)有設(shè)置ID時(shí),mongoDB會(huì)默認(rèn)給該條記錄設(shè)置一個(gè)ID("_id")。?
當(dāng)然你也可以設(shè)置自己指定的ID,如:(在mongoDB中執(zhí)行用db.users.save({_id:1,name:'bruce'});)?
當(dāng)你獲得了一個(gè)集合對(duì)象,你就可以把文檔插入到這個(gè)對(duì)象中。例如,存在一個(gè)JSON式的小文檔:
{
"name" : "MongoDB",
"type" : "database",
"count" : 1,
"info" : {
?? x : 203,
?? y : 102
? }
}
請(qǐng)注意,這個(gè)文檔包含一個(gè)內(nèi)部文檔。我們可以使用BasicDBObject類(lèi)來(lái)創(chuàng)建這個(gè)文檔,并且使用insert()方法方便地將它插入到集
合中。
BasicDBObject doc = new BasicDBObject();
doc.put("name", "MongoDB");
doc.put("type", "database");
doc.put("count", 1);
BasicDBObject info = new BasicDBObject();
info.put("x", 203);
info.put("y", 102);
doc.put("info", info);
coll.insert(doc);
批量插入?
List datas = new ArrayList();?
for (int i=0; i < 100; i++) {?
BasicDBObject bo = new BasicDBObject();?
bo.put("name", "bruce");?
bo.append("age", i);?
datas.add(bo);?
}?
coll.insert(datas);?
6 使用findOne()查找集合中第一個(gè)文檔
要查找我們上一步插入的那個(gè)文檔,可以簡(jiǎn)單地使用findOne()操作來(lái)獲取集合中第一個(gè)文檔。這個(gè)方法返回一個(gè)單一文檔(這是相對(duì)于使用DBCursor的find()操作的返回),這對(duì)于只有一個(gè)文檔或我們剛插入第一個(gè)文檔時(shí)很有用,因?yàn)榇藭r(shí)并不需要使用光標(biāo)。
DBObject myDoc = coll.findOne();
System.out.println(myDoc);
返回類(lèi)似:
{
"_id" : "ac907a1f5b9d5e4a233ed300" ,
"name" : "MongoDB" ,
"type" : 1 ,
"info" : {
? "x" : 203 ,
? "y" : 102} ,
"_ns" : "testCollection"
}
注意_id和_ns元素是由MongoDB自動(dòng)加入你的文檔。記住:MongoDB內(nèi)部存儲(chǔ)使用的元素名是以“_”做為開(kāi)始。
7 加入多種文檔
為了做更多有趣的查詢(xún)?cè)囼?yàn),讓我們向集合中加入多種文檔類(lèi)型,象:
{
"i" : value
}
可以通過(guò)循環(huán)來(lái)實(shí)現(xiàn)
for(int i = 0; i < 100; i++){
coll.insert(new BasicDBObject().append("i", i));
}
注意我們可以在一個(gè)集合中插入不同類(lèi)型的文檔,這就是我們所說(shuō)的“模式自由”(schema-free)。
8 統(tǒng)計(jì)文檔數(shù)量
使用getCount()方法
System.out.println(coll.getCount());
9 使用光標(biāo)(cursor)來(lái)獲取全部文檔
為了獲取集合中的所有文檔,我們可以使用find()方法。這個(gè)方法返回一上DBCursor對(duì)象,來(lái)允許我們將符合查詢(xún)條件的文檔迭代
出來(lái)。
DBCursor cur = coll.find();
while(cur.hasNext()){
System.out.println(cur.next());
}
10 在查詢(xún)中獲取單一文檔
我們可以創(chuàng)建一個(gè)查詢(xún),并傳遞給find()方法來(lái)獲取集合中所有文檔的一個(gè)子集。例如,我們想要查詢(xún)域名為"i",并且值為71的文檔:
BasicDBObject query = new BasicDBObject();
query.put("i", 71);
cur = coll.find(query);
while(cur.hasNext()){
System.out.println(cur.next());
}
類(lèi)轉(zhuǎn)換?
當(dāng)把一個(gè)類(lèi)對(duì)象存到mongoDB后,從mongoDB取出來(lái)時(shí)使用setObjectClass()將其轉(zhuǎn)換回原來(lái)的類(lèi)。?
public class Tweet implements DBObject {?
??? /* ... */?
}?
Tweet myTweet = new Tweet();?
myTweet.put("user", "bruce");?
myTweet.put("message", "fun");?
myTweet.put("date", new Date());?
collection.insert(myTweet);?
//轉(zhuǎn)換?
collection.setObjectClass(Tweet);?
Tweet myTweet = (Tweet)collection.findOne();?
11 使用條件查詢(xún)獲取集合
比較符?
"$gt": 大于?
"$gte":大于等于?
"$lt": 小于?
"$lte":小于等于?
"$in": 包含?
例如,我們想要查詢(xún)所有i>50的文檔:
BasicDBObject query = new BasicDBObject();
query.put("i", new BasicDBObject("$gt", 50));
cur = coll.find(query);
while(cur.hasNext()){
System.out.println(cur.next());
}
當(dāng)然,我們也可以做20 < i <= 30的查詢(xún)
BasicDBObject query = new BasicDBObject();
query.put("i", new BasicDBObject("$gt", 20).append("$lte", 30));
cur = coll.find(query);
while(cur.hasNext()){
System.out.println(cur.next());
}
正則表達(dá)式?
查詢(xún)所有名字匹配 /joh?n/i 的記錄?
Pattern pattern = Pattern.compile("joh?n", CASE_INSENSITIVE);?
BasicDBObject query = new BasicDBObject("name", pattern);?
DBCursor cursor = coll.find(query);?
12 創(chuàng)建索引
MongoDB支持索引,而且很容易在集合上增加索引。要?jiǎng)?chuàng)建索引,只需要指定要加索引的屬性,并且指定升序(1)或降序即可(-1)。
coll.createIndex(new BasicDBObject("i", 1));
13 獲取索引列表
List<DBObject> list = coll.getIndexInfo();
for(DBObject o : list){
System.out.println(o);
}
14 MongoDB管理函數(shù)
管理函數(shù)在com.mongodb.MongoAdmin類(lèi)中定義。
例A:獲取數(shù)據(jù)庫(kù)列表
MongoAdmin admin = new MongoAdmin();
for(String s : admin.getDatabaseNames()){
? System.out.println(s);
}
例B:獲取數(shù)據(jù)庫(kù)對(duì)象
Mongo m = admin.getDB("mydb");
例C:刪除數(shù)據(jù)庫(kù)
admin.dropDatabase("mydb");
15 用DBObject存儲(chǔ)JAVA對(duì)象
MongoDB for JAVA驅(qū)動(dòng)中提供了用于向數(shù)據(jù)庫(kù)中存儲(chǔ)普通對(duì)象的接口DBObject
例如,存在一個(gè)需要存儲(chǔ)的對(duì)象類(lèi)Tweet
public class Tweet implements DBObject{
/*...*/
}
可以使用如下代碼:
Tweet myTweet = new Tweet();
myTweet.put("user", userId);
myTweet.put("message", message);
myTweet.put("date", new Date());
collection.insert(myTweet);
當(dāng)一個(gè)文檔從MongoDB中取出時(shí),它會(huì)自動(dòng)把文檔轉(zhuǎn)換成DBObject接口類(lèi)型,要將它實(shí)例化為你的對(duì)象,需使用
DBCollection.setObjectClass()。
collection.setObjectClass(Tweet);
Tweet myTweet = (Tweet)collection.findOne();
16 JAVA驅(qū)動(dòng)的并發(fā)性
JAVA的MongoDB驅(qū)動(dòng)是線程安全的。如果你將它用在WEB服務(wù)中,可以創(chuàng)建它的一個(gè)單例,并在所有請(qǐng)求中使用它。
然而,如果你需要在一個(gè)會(huì)話(例如HTTP請(qǐng)求)中保證事務(wù)一致性,也許你會(huì)希望在這個(gè)會(huì)話中對(duì)驅(qū)動(dòng)使用同一個(gè)端口。這僅僅在
請(qǐng)求量非常大的環(huán)境中,例如你經(jīng)常會(huì)讀取剛寫(xiě)入的數(shù)據(jù)。
為了這一點(diǎn),你需要使用如下代碼:
Mongo m;
m.restartStart();
// code.........
m.requestDone();
源碼下載地址
參考:
http://www.iteye.com/blogs/tag/NoSQL
http://blog.nosqlfan.com/html/2215.html
http://josh-persistence.iteye.com/blog/1882436
http://www.mongodb.org/display/DOCS/Manual
http://blog.nosqlfan.com/html/342.html
http://myeyeofjava.iteye.com/blog/1296575
http://docs.mongodb.org/ecosystem/drivers/java/
?
總結(jié)
以上是生活随笔為你收集整理的mongoDB入门必读(概念与实战并重)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 不可新增人员
- 下一篇: Servlet基本_オブジェクトのスコー