MongoDB學習筆記(一)


1.MongoDB簡介

 

MongoDB介紹

MongoDB是面向文檔的非關系型數據庫,不是現在使用最普遍的關系型數據庫,其放棄關系模型的原因就是為了獲得更加方便的擴展、穩定容錯等特性。面向文檔的基本思路就是:將關系模型中的“行”的概念換成“文檔(document)”模型。面向文檔的模型可以將文檔和數組內嵌到文檔中。因此,實際中可以用一條數據表示非常復雜的結構。
MongoDB沒有預定義模式:文檔的鍵(key)和值(value)不再是固定的類型和大小,而且根據需求要添加或者刪除字段變得更容易了。由於沒有模式需要更改,通常不需要遷移大量數據。不必將所有數據都放到一個模子里面,應用層可以處理新增或丟失的鍵。這樣開發者可以非常容易地變更數據模型。
實際應用中,隨着數據量的增大,數據庫都要進行擴展。擴展有縱向擴展和橫向擴展。縱向擴展是使用計算能力更強的機器,也是最省力的方法,但是很容易達到物理極限,無論花多少錢也買不到最新的機器了。橫向擴展就是通過分區將數據分散到更多的機器上。MongoDB的設計采用橫向擴展。面向文檔的數據模型使它很容易地在多台服務器之間進行數據分割。還可以自動處理跨集群的數據和負載,自動重新分配文檔,以及將用戶請求路由到正確的機器上。開發者根本不用考慮數據庫層次的擴展問題,需要擴展數據庫時,在集群中添加機器即可,MongoDB會自動處理后續的事情。
MongoDB有如上各種特性,但為了達到這些,他也放棄了關系型數據庫的某些功能如表連接join和復雜的多行事務。

2017-05-12_214955.png-8kB 
直觀了解: 
2017-05-17_165633.png-13kB

 

MongoDB的優勢與劣勢

 

優勢

  1. 快速!基於內存,將熱數據存放在物理內存中(不僅僅只是索引和少部分數據),從而提高了整體速度和效率。
  2. 高擴展性!MongoDB的高可用和集群架構擁有十分高的擴展性。
  3. 自身的FailOver機制!在副本集中,當主庫遇到問題,無法繼續提供服務的時候,副本集將選舉一個新的主庫繼續提供服務。
  4. JSon格式的數據!MongoDB的Bson和JSon格式的數據十分適合文檔格式的存儲與查詢。
 

劣勢

  1. 應用經驗少!由於NoSQL興起時間短,應用經驗相比關系型數據庫較少。
  2. 由於以往用到的都是關系型數據庫,可能會造成使用者一開始的不適應。
  3. 無事務機制!MongoDB本身沒有自帶事務機制,若需要在MongoDB中實現事務機制,需通過一個額外的表,從邏輯上自行實現事務。

 

2.MongoDB與MYSQL對比

數據庫 MongoDB MySQL
數據庫模型 非關系型 關系型
存儲方式 以類JSON的文檔的格式存儲 不同引擎有不同的存儲方式
查詢語句 MongoDB查詢方式(類似JavaScript的函數) SQL語句
數據處理方式 基於內存,將熱數據存放在物理內存中,從而達到高速讀寫 不同引擎有自己的特點
成熟度 新興數據庫,成熟度較低 成熟度高
廣泛度 NoSQL數據庫中,比較完善且開源,使用人數在不斷增長 開源數據庫,市場份額不斷增長
事務性 僅支持單文檔事務操作,弱一致性 支持事務操作
占用空間 占用空間大 占用空間小
join操作 MongoDB沒有join MySQL支持join

下面是Mongodb與Mysql的操作命令的對比: 
2017-05-05_102256.png-15kB


 

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: 
2017-05-05_154321.png-3.8kB 
shell是一個功能完備的JavaScript解釋器,可運行任意的JavaScript程序。這里不做示例。 
MongoDB的默認數據庫為"db",該數據庫存儲在data目錄中。 
1.選擇數據庫

#選擇名test數據庫
use tset

  

2017-05-05_154819.png-1.6kB 
如果忘記了數據庫名稱可以輸入如下代碼查詢所有數據庫名稱:"show dbs" 命令可以顯示所有數據的列表

 
show dbs

  

2017-05-05_154952.png-2.7kB 
查看數據庫中的集合名:

 
show collections

  

結果如圖所示: 
2017-05-05_161235.png-2kB 
下表列出了 RDBMS 與 MongoDB 對應的術語: 
2017-05-17_170031.png-4.5kB

 

插入文檔

insert函數可將一個文檔插入到集合中去。以一個博客舉例。先創建一個叫post的變量(JavaScript對象)有三個鍵和對應的屬性。插入代碼:

 
db.blog.insert(post)

如圖所示: 
2017-05-05_161551.png-6kB 
批量插入

 
db.blog.insertMany([{"_id":0},{"_id":1},{"_id":2}])

  

2017-05-05_171812.png-3.5kB

 

查詢文檔

查詢代碼如下:

 
db.blog.find()

如圖所示: 
2017-05-05_161943.png-5kB 
多出來的"_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';

2017-05-05_162233.png-7.7kB

 

修改文檔

如果給博客新增一個評論功能,則需要新增key-value,用於保存評論數組。

 
post.comments = []

之后用新版本的文檔替換舊版本:

 
db.blog.update({"title":"My Blog Post"},post)

2017-05-05_162757.png-7.3kB

使用修改器:

"$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":"joe@gmail.com"}})
"$push":刪除數組里的元素.("$pop":將數組看成隊列或棧,從兩端刪除。"$pull":將所匹配到的數組中的值刪除,而不是只刪除一個)

刪除文檔

db.blog.remove({"title":"My Blog Post"})

2017-05-05_162941.png-2.9kB 
刪除整個集合用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());
}

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM