1.MongoDB簡介 MongoDB介紹 MongoDB是面向文檔的非關係型資料庫,不是現在使用最普遍的關係型資料庫,其放棄關係模型的原因就是為了獲得更加方便的擴展、穩定容錯等特性。面向文檔的基本思路就是:將關係模型中的“行”的概念換成“文檔(document)”模型。面向文檔的模型可以將文檔和數 ...
1.MongoDB簡介
MongoDB介紹
MongoDB是面向文檔的非關係型資料庫,不是現在使用最普遍的關係型資料庫,其放棄關係模型的原因就是為了獲得更加方便的擴展、穩定容錯等特性。面向文檔的基本思路就是:將關係模型中的“行”的概念換成“文檔(document)”模型。面向文檔的模型可以將文檔和數組內嵌到文檔中。因此,實際中可以用一條數據表示非常複雜的結構。
MongoDB沒有預定義模式:文檔的鍵(key)和值(value)不再是固定的類型和大小,而且根據需求要添加或者刪除欄位變得更容易了。由於沒有模式需要更改,通常不需要遷移大量數據。不必將所有數據都放到一個模子裡面,應用層可以處理新增或丟失的鍵。這樣開發者可以非常容易地變更數據模型。
實際應用中,隨著數據量的增大,資料庫都要進行擴展。擴展有縱向擴展和橫向擴展。縱向擴展是使用計算能力更強的機器,也是最省力的方法,但是很容易達到物理極限,無論花多少錢也買不到最新的機器了。橫向擴展就是通過分區將數據分散到更多的機器上。MongoDB的設計採用橫向擴展。面向文檔的數據模型使它很容易地在多台伺服器之間進行數據分割。還可以自動處理跨集群的數據和負載,自動重新分配文檔,以及將用戶請求路由到正確的機器上。開發者根本不用考慮資料庫層次的擴展問題,需要擴展資料庫時,在集群中添加機器即可,MongoDB會自動處理後續的事情。
MongoDB有如上各種特性,但為了達到這些,他也放棄了關係型資料庫的某些功能如表連接join和複雜的多行事務。
直觀瞭解:
MongoDB的優勢與劣勢
優勢
- 快速!基於記憶體,將熱數據存放在物理記憶體中(不僅僅只是索引和少部分數據),從而提高了整體速度和效率。
- 高擴展性!MongoDB的高可用和集群架構擁有十分高的擴展性。
- 自身的FailOver機制!在副本集中,當主庫遇到問題,無法繼續提供服務的時候,副本集將選舉一個新的主庫繼續提供服務。
- JSon格式的數據!MongoDB的Bson和JSon格式的數據十分適合文檔格式的存儲與查詢。
劣勢
- 應用經驗少!由於NoSQL興起時間短,應用經驗相比關係型資料庫較少。
- 由於以往用到的都是關係型資料庫,可能會造成使用者一開始的不適應。
- 無事務機制!MongoDB本身沒有自帶事務機制,若需要在MongoDB中實現事務機制,需通過一個額外的表,從邏輯上自行實現事務。
2.MongoDB與MYSQL對比
資料庫 | MongoDB | MySQL |
---|---|---|
資料庫模型 | 非關係型 | 關係型 |
存儲方式 | 以類JSON的文檔的格式存儲 | 不同引擎有不同的存儲方式 |
查詢語句 | MongoDB查詢方式(類似JavaScript的函數) | SQL語句 |
數據處理方式 | 基於記憶體,將熱數據存放在物理記憶體中,從而達到高速讀寫 | 不同引擎有自己的特點 |
成熟度 | 新興資料庫,成熟度較低 | 成熟度高 |
廣泛度 | NoSQL資料庫中,比較完善且開源,使用人數在不斷增長 | 開源資料庫,市場份額不斷增長 |
事務性 | 僅支持單文檔事務操作,弱一致性 | 支持事務操作 |
占用空間 | 占用空間大 | 占用空間小 |
join操作 | MongoDB沒有join | MySQL支持join |
下麵是Mongodb與Mysql的操作命令的對比:
MongoDB基礎知識與CRUD
1.文檔(document):相當於傳統關係型資料庫的“行”,但比傳統行表示的信息更加複雜。例如:
{"name":"jack","age":18,"sex":"male"}
2.集合(collection):這個在MongoDB中代表一組文檔,類似於關係型資料庫中的表。但在MongoDB中的表(就是集合)是沒有模式的,你可以將完全不同的文檔放入同一個集合中.但在實際使用中,為特定集合隱性規定一種模式。註:當集合里沒有任何文檔時集合其實也是不存在的。當第一個文檔插入時,集合就會被創建。
3.資料庫(database):在MongoDB中,一組集合可以組成一個資料庫。一個MongoDB實例可以承載多個資料庫。每個資料庫都有獨立的許可權控制。在實際應用中,通常,一個應用的所有數據放置在一個資料庫中。
4.數據類型:MongoDB中的文檔類似於JSON。JSON是一種簡單的數據交換格式,在數據類型方面,只支持:null,布爾,數字,字元串,數組和對象。這幾種類型在某些實際應用中表現力還是不夠,比如JSON本身不直接支持日期類型,對於數字,JSON本身也沒法區分整數和浮點數,更不能區分32位數字和64位數字。為此,MongoDB再保留了JSON的各類特性外,又為其添加了一些數據類型。
1.null:用於表示空值或不存在的欄位。Shell中這樣表示:{"x":null}
2.布爾:有兩個值,true和false。Shell中這樣使用:{"x":true}
3.數字:Shell中數字均為64位浮點數,如在Shell中{"x":3.14}
和{"x":3}
這兩個文檔中的值均是64位的浮點數。
4.字元串:這個用的最廣,Shell中這樣表示:{"x":"hello world!"}
5.日期:這個在數據存儲時,存儲的是從標準紀元開始的毫秒數,沒有存儲時區信息。
6.正則表達式:文檔中可以包含正則表達式,採用JavaScript的正則表達式語法即可,Shell中這樣表示:{"x":/foobar/i}
。
7.數組:數組是一組值,既可以表示為有序對象(列表,棧,隊列等)也可以表示無序對象(集合),Shell中這樣表示一個數組:{"things":["pie",3.14]}
。
8.內嵌文檔:把一個文檔整個作為另一個文檔某一個鍵對應的值。
其他包括二進位數據,代碼等。
MongoDB入門(Shell基本操作)
運行mongo啟動shell:
shell是一個功能完備的JavaScript解釋器,可運行任意的JavaScript程式。這裡不做示例。
MongoDB的預設資料庫為"db",該資料庫存儲在data目錄中。
1.選擇資料庫
#選擇名test資料庫 use tset
如果忘記了資料庫名稱可以輸入如下代碼查詢所有資料庫名稱:"show dbs" 命令可以顯示所有數據的列表
show dbs
查看資料庫中的集合名:
show collections
結果如圖所示:
下表列出了 RDBMS 與 MongoDB 對應的術語:
插入文檔
insert函數可將一個文檔插入到集合中去。以一個博客舉例。先創建一個叫post的變數(JavaScript對象)有三個鍵和對應的屬性。插入代碼:
db.blog.insert(post)
如圖所示:
批量插入
db.blog.insertMany([{"_id":0},{"_id":1},{"_id":2}])
查詢文檔
查詢代碼如下:
db.blog.find()
如圖所示:
多出來的"_id"就是MongoDB自動創建的預設為ObjectID類型的對象。在一個集合里,每個文檔都由唯一的"_id",確保集合中的每個文檔都能被唯一標識,它採用12位元組的存儲空間,由24個16進位數字組成,可分為四部分組成:
{0,1,2,3} | {4,5,6} | {7,8} | {9,10,11} |
---|---|---|---|
時間戳 | 機器碼 | PID(線程碼) | 自增計數器 |
如果插入文檔時沒有"_id"鍵,系統會為我們自動創建一個。
若只想查看一個文檔,可以用findOne:
db.blog.findOne()
查詢具體的某一個文檔那麼就要以json的形式添加查詢條件,例如:
db.blog.find({"title":"My Blog Post"})
以上實例中類似於 WHERE 語句:WHERE title = 'My Blog Post';
修改文檔
如果給博客新增一個評論功能,則需要新增key-value,用於保存評論數組。
post.comments = []
之後用新版本的文檔替換舊版本:
db.blog.update({"title":"My Blog Post"},post)
使用修改器:
"$Set":用來指定一個欄位的值,若欄位不存在,則創建它。
db.users.update({"sex":"male"},{"$Set":{"gift":"happy birthday!"}}) /*這樣只會更新一個文檔,若要更新多個文檔,則需要將update的第四個參數設置為true*/ db.users.update({"sex":"male"},{"$Set":{"gift":"happy birthday!"}},false,true)
"$inc":用來增加已有鍵的值,若鍵不存在,就創建它。(與"$Set"類似,專門用來增加數字的,只能用於整形,長整型,雙精度浮點型)
db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":50}})
"$push":會向已有的數組末尾加入一個元素,若數組不存在,則創建數組。與"$each"自操作符一同使用可以一次添加多個值。
db.stock.ticker.update({"_id":"1"},{"$push":{"hourly":{"$each":[562.667,562.790,562.123]}}})
"$addToSet":可以避免重覆插入。若數組內已有相同數據,則不差入。與"$each"自操作符一同使用可以一次添加多個值。
db.users.update({"_id""1},{"$addToSet":{"emails":"[email protected]"}})
"$push":刪除數組裡的元素.("$pop":將數組看成隊列或棧,從兩端刪除。"$pull":將所匹配到的數組中的值刪除,而不是只刪除一個)
刪除文檔
db.blog.remove({"title":"My Blog Post"})
刪除整個集合用drop()
db.blog.drop()
索引
MongoDB使用 ensureIndex() 方法來創建索引。
db.COLLECTION_NAME.ensureIndex({KEY:1})
語法中 Key 值為你要創建的索引欄位,1為指定按升序創建索引,如果你想按降序來創建索引指定為-1即可。
當然也可以給多個欄位建立索引
db.col.ensureIndex({"title":1,"description":-1})
管道聚合
MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理。管道操作是可以重覆的。
表達式:處理輸入文檔並輸出。表達式是無狀態的,只能用於計算當前聚合管道的文檔,不能處理其它的文檔。
這裡我們介紹一下聚合框架中常用的幾個操作:
- $project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用於創建計算結果以及嵌套文檔。
db.article.aggregate( { $project : { title : 1 , author : 1 , }} );
- $match:用於過濾數據,只輸出符合條件的文檔。
db.articles.aggregate( [ { $match : { score : { $gt : 70, $lte : 90 } } }, { $group: { _id: null, count: { $sum: 1 } } } ] );
- $limit:用來限制MongoDB聚合管道返回的文檔數。
db.article.find().limit
- $skip:在聚合管道中跳過指定數量的文檔,並返回餘下的文檔。
db.article.aggregate( { $skip : 5 });
-
$group:將集合中的文檔分組,可用於統計結果。
-
$sort:將輸入文檔排序後輸出。
Java操作MongoDB
連接資料庫
連接資料庫,你需要指定資料庫名稱,如果指定的資料庫不存在,mongo會自動創建資料庫。
所需jar包: mongo-java-driver-3.2.2.jar
連接資料庫的Java代碼如下:
1 import com.mongodb.MongoClient; 2 import com.mongodb.client.MongoDatabase; 3 public class MongoDBJDBC{ 4 public static void main( String args[] ){ 5 try{ 6 // 連接到 mongodb 服務 7 MongoClient mongoClient = new MongoClient( "localhost" , 27017 ); 8 // 連接到資料庫 9 MongoDatabase mongoDatabase = mongoClient.getDatabase("test"); 10 System.out.println("Connect to database successfully"); 11 }catch(Exception e){ 12 System.err.println( e.getClass().getName() + ": " + e.getMessage() ); 13 } 14 } 15 }
創建集合:
我們可以使用 com.mongodb.client.MongoDatabase 類中的createCollection()來創建集合
代碼片段如下:
import com.mongodb.MongoClient; import com.mongodb.client.MongoDatabase; public class MongoDBJDBC{ public static void main( String args[] ){ try{ // 連接到 mongodb 服務 MongoClient mongoClient = new MongoClient( "localhost" , 27017 ); // 連接到資料庫 MongoDatabase mongoDatabase = mongoClient.getDatabase("test"); System.out.println("Connect to database successfully"); mongoDatabase.createCollection("test"); System.out.println("集合創建成功"); }catch(Exception e){ System.err.println( e.getClass().getName() + ": " + e.getMessage() ); } } }
插入文檔
//插入文檔 /** * 1. 創建文檔 org.bson.Document 參數為key-value的格式 * 2. 創建文檔集合List<Document> * 3. 將文檔集合插入資料庫集合中 mongoCollection.insertMany(List<Document>) 插入單個文檔可以用 mongoCollection.insertOne(Document) * */ Document document = new Document("title", "MongoDB"). append("description", "database"). append("likes", 100). append("by", "Fly"); List<Document> documents = new ArrayList<Document>(); documents.add(document); collection.insertMany(documents); System.out.println("文檔插入成功");
查詢文檔
//檢索所有文檔 /** * 1. 獲取迭代器FindIterable<Document> * 2. 獲取游標MongoCursor<Document> * 3. 通過游標遍歷檢索出的文檔集合 * */ FindIterable<Document> findIterable = collection.find(); MongoCursor<Document> mongoCursor = findIterable.iterator(); while(mongoCursor.hasNext()){ System.out.println(mongoCursor.next()); }
修改文檔
//更新文檔 將文檔中likes=100的文檔修改為likes=200 collection.updateMany(Filters.eq("likes", 100), new Document("$set",new Document("likes",200))); //檢索查看結果 FindIterable<Document> findIterable = collection.find(); MongoCursor<Document> mongoCursor = findIterable.iterator(); while(mongoCursor.hasNext()){ System.out.println(mongoCursor.next()); }
刪除文檔
//刪除符合條件的第一個文檔 collection.deleteOne(Filters.eq("likes", 200)); //刪除所有符合條件的文檔 collection.deleteMany (Filters.eq("likes", 200)); //檢索查看結果 FindIterable<Document> findIterable = collection.find(); MongoCursor<Document> mongoCursor = findIterable.iterator(); while(mongoCursor.hasNext()){ System.out.println(mongoCursor.next()); }