MongoDB

一、MongoDB 簡介

1. 百科

MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫。由C++語言編寫。旨在為WEB應(yīng)用提供可擴展的高性能數(shù)據(jù)存儲解決方案。

MongoDB是一個介于關(guān)系數(shù)據(jù)庫和非關(guān)系數(shù)據(jù)庫之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫當中功能最豐富,最像關(guān)系數(shù)據(jù)庫的。它支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類似json的bson格式,因此可以存儲比較復(fù)雜的數(shù)據(jù)類型。Mongo最大的特點是它支持的查詢語言非常強大,其語法有點類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實現(xiàn)類似關(guān)系數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。

2. 與MySQL相比:

  • 數(shù)據(jù)模型,MongoDB是面向文檔的數(shù)據(jù)庫,MySQL是關(guān)系型數(shù)據(jù)庫。
  • 查詢語言,MongoDB不支持join,MySQL支持join。
  • 擴展性和性能,MongoDB使用可水平擴展的架構(gòu),MySQL使用垂直擴展的架構(gòu)。
  • 可靠性,MongoDB目前只支持單文檔事務(wù),MySQL支持復(fù)雜事務(wù)操作。

3. 與Redis相比:

  • 數(shù)據(jù)存儲方式:MongoDB使用文檔存儲方式,Redis使用鍵值對存儲方式。
  • 數(shù)據(jù)類型:MongoDB可以存儲各種類型的數(shù)據(jù),包括文本、數(shù)字、日期、數(shù)組、嵌套文檔等等,Redis主要用于存儲簡單的數(shù)據(jù)類型,如字符串、哈希表、列表、集合等等。
  • 存儲方式:MongoDB使用磁盤存儲數(shù)據(jù),Redis則是將數(shù)據(jù)存儲在內(nèi)存中。因此,MongoDB可以存儲更大量級的數(shù)據(jù),而Redis則更適合處理較小、經(jīng)常被訪問的數(shù)據(jù)。
  • 數(shù)據(jù)訪問:MongoDB提供強大的查詢檢索功能,而Redis僅支持基本的查詢操作。
  • 擴展性:MongoDB可以水平擴展,支持分布式架構(gòu),而Redis主要是通過主從復(fù)制的方式實現(xiàn)高可用性和可擴展性。

4. 適合的場景:

  • 數(shù)據(jù)量大。
  • 讀寫操作頻繁。
  • 數(shù)據(jù)價值較低,對事務(wù)要求不高。

二、MongoDB 創(chuàng)建/刪除數(shù)據(jù)庫

db.cloneDatabase("127.0.0.1");  // 從指定主機上克隆數(shù)據(jù)庫

use database;

db.database.insertOne({"name":"B"});

db.dropDatabase();

三、MongoDB 創(chuàng)建/刪除集合

db.createCollection("database");

db.database.drop();

四、插入/刪除文檔

db.collections.insert(obj)

db.collections.insertOne( obj, < optional params > ):返回插入主鍵

db.collections.insertMany( [objects], < optional params > ):批量插入,返回插入的主鍵

db.users.insertMany([
  {
    "name": "Johs",
    "age": 10,
    "email": "johs@example.com"
  },
  {
    "name": "John",
    "age": 30,
    "email": "john@example.com"
  },
  {
    "name": "Jane",
    "age": 25,
    "email": "jane@example.com"
  },
  {
    "name": "Bob",
    "age": 40,
    "email": "bob@example.com"
  }
])
db.users.insertMany

在創(chuàng)建集合期間,MongoDB 在 _id 字段上創(chuàng)建唯一索引,該索引可防止客戶端插入兩個具有相同的文檔

db.collections.save(obj):主鍵不存在插入,存在則替換

db.collections.drop():刪除集合

db.collections.remove({"字段":"值"}):刪除滿足條件的所有數(shù)據(jù)

db.collections.remove({"字段":"值"},true):刪除滿足條件的第一條數(shù)據(jù)


五、查詢文檔

db.collections.find(<條件>):查找所有文檔,相當于 select * from user
條件字段如果是字符串,表示包含;如果是數(shù)組,表示精確匹配;$all:匹配多個元素;$size:元素個數(shù);$slice:截??;$elemMatch:數(shù)組中是否有一個元素同時滿足所有條件;$type:字段類型;$exists:字段是否存在;null:字段值是否為null或沒有該字段

db.collection.findOne()

  • 比較查詢:$lt 、$lte 、$gt 、$gte 、$ne

    db.users.find({"name" : {"$ne" : "John"}});
    
    db.users.find({"age" : {"$gte":20,"$lte": 30}});
    
  • 范圍查詢:$in、$nin

    db.users.find({"age" : {"$in" : [10, 30]}});// in不是between,是 = and =
    
  • $where:通過js函數(shù)自定義查詢條件,此時不走索引

    db.users.find({"$where" : "function() { return this.age == 10; }"});
    
  • 正則表達式和數(shù)組

    db.users.find({"name" : {"$regex" : "Ja" }});
    
    db.users.find({"name" : {"$regex" : /Ja/ }});
    
    db.users.find({"name" : /Ja/ });
    
  • 條件查詢:$and、$or

    db.users.find({"$or":[{"name":"Bob"},{"age":30}]});
    
  • 特殊函數(shù):distinct、count、limit、skip、sort(正數(shù)升序)

    db.users.distinct();
    
    db.users.countDocuments();
    
    db.users.find().sort({"age":-1}).skip(1).limit(3);
    

聚合框架aggregate

  • $match篩選:相當于sql中的where

  • $project投射:查詢指定字段、對字段起別名、使用算術(shù)表達式 $add、$subtract、$multiply、$divide、$mod 處理字段、$substrCP截取、$concat拼接、$toUpper/Lower轉(zhuǎn)大小寫、日期表達式、$cmp比較非字符串類型、$strcasecmp比較字符串、$and/or/not、$cond 三位運算符、ifNull(bool, default_value)

  • $group 分組、$unwind拆分、$sort、$limit、$skip

    示例:
    db.user.aggregate(
      {"$match": {"age": {"$gte" : 10} }},
      {"$group": {"_id": "$class", "count": {"$sum": 1}}},
      {"$sort": {"count": -1}},
      {"$skip": 1},
      {"$limit": 1}
    )
    上述聚合函數(shù)相當于:
    SELECT class, COUNT(*) AS count FROM user WHERE age >= 10 GROUP BY classORDER BY count DESC LIMIT 1 OFFSET 1;
    

六、MongoDB 更新文檔

db.collection.update(<query>,<update>,
?{
??upsert: <boolean>,
??multi: <boolean>,
??writeConcern: <document>
?}
)

  • query : update的查詢條件,類似sql update查詢內(nèi)where后面的。
  • update : update的對象和一些更新的操作符(如,inc...)等,也可以理解為sql update查詢內(nèi)set后面的
  • upsert : 可選,這個參數(shù)的意思是,如果不存在update的記錄,是否插入objNew,true為插入,默認是false,不插入。
  • multi : 可選,mongodb 默認是false,只更新找到的第一條記錄,如果這個參數(shù)為true,就把按條件查出來多條記錄全部更新。
  • writeConcern :可選,拋出異常的級別。
  • 默認整體替換掉滿足條件的文檔而不是單獨的修改指定字段的值

db.collection.update(query, update, insertOrUpdate)
若insertOrUpdate為true,則更新策略變?yōu)椴淮嬖趧t添加,存在則更新

db.collection.update(query, update, insertOrUpdate, multiUpdate) 批量更新

  • $set:字段存在則修改,不存在則添加。對應(yīng)update中整個文檔進行替換

  • $unset:刪除字段。

  • $inc:字段遞增/減

  • $push:字段尾部添加元素,若字段不存在則創(chuàng)建數(shù)組

  • $push + $each:添加多個元素

      db.user.update({"_id": 1}, {"$push": {"hobby": {"$each": ["money", "xiaojiejie"]}}})
    
  • $addToSet:向數(shù)組尾部添加不存在的元素,如果存在則不添加

  • $pop:彈出數(shù)組的頭部元素或尾部元素: -1:頭部,1:尾部。

  • $pull:刪除數(shù)組中的指定的值。

db.collection.findAndModify({ “query”: xxx, “update”: xxx,upsert):查找滿足添加的值并返回,并且修改滿足條件的第一條文檔


七、MongoDB 索引

db.collection.createIndex(keys, options); //創(chuàng)建索引
如果查詢時發(fā)現(xiàn)沒有使用到索引,可以使用hint函數(shù)強制使用索引查詢

1. 索引類型

  • 唯一索引 unique;
  • 稀疏索引 sparse:包含索引必須唯一,不包含不用校驗,對應(yīng)唯一索引校驗null
  • 復(fù)合索引
  • TTL 索引: 設(shè)置文檔的緩存時間,時間到了會自動刪除掉
  • 全文索引 text:便于大文本查詢(如概要、文章等長文本)
  • 二維平面索引:便于2d平面查詢;
  • 地理空間索引:便于地理查詢

2. 索引選項

  • 復(fù)合索引 name:"", 自定義索引的名稱,不配置系統(tǒng)會有默認的索引名。
  • 復(fù)合索引 background: true, 默認是前臺模式, 創(chuàng)建索引是一件即費事又耗費資源的事情,創(chuàng)建索引是在前臺模式或者后臺模式下創(chuàng)建,在前臺模式下創(chuàng)建非常快,但是當有讀寫請求時會堵塞,在后臺模式下當有讀寫請求時并不堵塞,但是創(chuàng)建索引就會暫時暫停,后臺模式要比前臺模式慢的多。
  • 復(fù)合索引 unique/sparse: true,索引
  • 復(fù)合索引 dropDups: true,是否強制刪除其他重復(fù)的文檔,默認不刪除,當索引鍵值重復(fù)時創(chuàng)建失敗。

3. 對于索引的使用效率

  • 復(fù)合索引索引鍵基數(shù)越大,效率越高。一些特殊的操作符不能使用索引,一般取反的操作符索引利用率都比較低。
  • 復(fù)合索引如果能使用操作符盡量不要使用作符,因為or是執(zhí)行兩次查詢操作,然后將結(jié)果合并起來,類似于union all,能使用in(單次查詢)就不要使用or操作符。

八、MongoDB ObjectId

MongoDB中存儲的文檔必須有一個"_id"鍵。這個鍵的值可以是任何類型的,默認是個ObjectId對象。在一個集合里面,每個文檔都有唯一的"_id"值,來確保集合里面每個文檔都能被唯一標識。

MongoDB采用ObjectId,而不是其他比較常規(guī)的做法(比如自動增加的主鍵)的主要原因,因為在多個 服務(wù)器上同步自動增加主鍵值既費力還費時。

ObjectId 是一個12字節(jié) BSON 類型數(shù)據(jù),有以下格式:

  • 前4個字節(jié)表示時間戳
  • 接下來的3個字節(jié)是機器標識碼
  • 緊接的兩個字節(jié)由進程id組成(PID)
  • 最后三個字節(jié)是隨機數(shù)。
ObjectId();

ObjectId("64d34d4fe31e1a71dd3e5355").getTimestamp(); // getTimestamp 函數(shù)可以獲取文檔的創(chuàng)建時間

九、MongoDB 復(fù)制

MongoDB復(fù)制是將數(shù)據(jù)同步在多個服務(wù)器的過程。復(fù)制提供了數(shù)據(jù)的冗余備份,并在多個服務(wù)器上存儲數(shù)據(jù)副本,提高了數(shù)據(jù)的可用性, 并可以保證數(shù)據(jù)的安全性。復(fù)制還允許您從硬件故障和服務(wù)中斷中恢復(fù)數(shù)據(jù)。

MongoDB復(fù)制結(jié)構(gòu)圖

mongodb的復(fù)制至少需要兩個節(jié)點。其中一個是主節(jié)點,負責處理客戶端請求,其余的都是從節(jié)點,負責復(fù)制主節(jié)點上的數(shù)據(jù)。

主節(jié)點記錄在其上的所有操作oplog,從節(jié)點定期輪詢主節(jié)點獲取這些操作,然后對自己的數(shù)據(jù)副本執(zhí)行這些操作,從而保證從節(jié)點的數(shù)據(jù)與主節(jié)點一致。

1. 添加副本集

replSet 選項

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
實例:
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
以上實例會啟動一個名為rs0的MongoDB實例,其端口號為27017。

啟動后打開命令提示框并連接上mongoDB服務(wù)。
在Mongo客戶端使用命令rs.initiate()來啟動一個新的副本集,使用rs.conf()來查看副本集的配置,使用 rs.status() 查看副本集狀態(tài)。

rs.add 命令

rs.add(HOST_NAME:PORT)
實例:
假設(shè)你已經(jīng)啟動了一個名為mongod1.net,端口號為27017的Mongo服務(wù)。 在客戶端命令窗口使用rs.add() 命令將其添加到副本集中,命令如下所示:
rs.add("mongod1.net:27017")

MongoDB中你只能通過主節(jié)點將Mongo服務(wù)添加到副本集中,判斷當前運行的Mongo服務(wù)是否為主節(jié)點可以使用命令db.isMaster() 。

MongoDB的副本集與我們常見的主從有所不同,主從在主機宕機后所有服務(wù)將停止,而副本集在主機宕機后,副本會接管主節(jié)點成為主節(jié)點,不會出現(xiàn)宕機的情況。


十、MongoDB 分片

在Mongodb里面存在另一種集群,就是分片技術(shù),可以滿足MongoDB數(shù)據(jù)量大量增長的需求。

當MongoDB存儲海量的數(shù)據(jù)時,一臺機器可能不足以存儲數(shù)據(jù),也可能不足以提供可接受的讀寫吞吐量。這時,我們就可以通過在多臺機器上分割數(shù)據(jù),使得數(shù)據(jù)庫系統(tǒng)能存儲和處理更多的數(shù)據(jù)。

MongoDB分片集群結(jié)構(gòu)分布

上圖中主要有如下所述三個主要組件:

  • Shard:
    用于存儲實際的數(shù)據(jù)塊,實際生產(chǎn)環(huán)境中一個shard server角色可由幾臺機器組個一個replica set承擔,防止主機單點故障
  • Config Server:
    mongod實例,存儲了整個 ClusterMetadata,其中包括 chunk信息。
  • Query Routers:
    前端路由,客戶端由此接入,且讓整個集群看上去像單一數(shù)據(jù)庫,前端應(yīng)用可以透明使用。

1. 為什么使用分片

  • 復(fù)制所有的寫入操作到主節(jié)點
  • 延遲的敏感數(shù)據(jù)會在主節(jié)點查詢
  • 單個副本集限制在12個節(jié)點
  • 當請求量巨大時會出現(xiàn)內(nèi)存不足。
  • 本地磁盤不足
  • 垂直擴展價格昂貴
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容