MongoDB 是一個基于分布式文件存儲的數據庫。由 C++ 語言編寫,旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。MongoDB 是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。MongoDB 將數據存儲為一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔類似于 JSON 對象。字段值可以包含其他文檔,數組及文檔數組。
什么是NoSQL?
NoSQL,指的是非關系型的數據庫。NoSQL有時也稱作Not Only SQL的縮寫,是對不同于傳統的關系型數據庫的數據庫管理系統的統稱。NoSQL用于超大規模數據的存儲。(例如谷歌或Facebook每天為他們的用戶收集萬億比特的數據)。這些類型的數據存儲不需要固定的模式,無需多余操作就可以橫向擴展。
為什么使用NoSQL ?
今天我們可以通過第三方平臺(如:Google,Facebook等)可以很容易的訪問和抓取數據。用戶的個人信息,社交網絡,地理位置,用戶生成的數據和用戶操作日志已經成倍的增加。我們如果要對這些用戶數據進行挖掘,那SQL數據庫已經不適合這些應用了, NoSQL數據庫的發展也卻能很好的處理這些大的數據。
分布式系統
分布式系統(distributed system)由多臺計算機和通信的軟件組件通過計算機網絡連接(本地網絡或廣域網)組成,是建立在網絡之上的軟件系統。正是因為軟件的特性,所以分布式系統具有高度的內聚性和透明性。因此,網絡和分布式系統之間的區別更多的在于高層軟件(特別是操作系統)而不是硬件。分布式系統可以應用在在不同的平臺上如:Pc、工作站、局域網和廣域網上等。
RDBMS vs NoSQL
RDBMS
- 高度組織化結構化數據
- 結構化查詢語言(SQL)
- 數據和關系都存儲在單獨的表中。
- 數據操縱語言,數據定義語言
- 嚴格的一致性
- 基礎事務
NoSQL
- 代表著不僅僅是SQL
- 沒有聲明性查詢語言
- 沒有預定義的模式
-鍵 - 值對存儲,列存儲,文檔存儲,圖形數據庫
- 最終一致性,而非ACID屬性
- 非結構化和不可預知的數據
- CAP定理
- 高性能,高可用性和可伸縮性
數據類型
下面為MongoDB中常用的幾種數據類型:
1.object id:文檔id
2.string:字符串,最常用,必須是有效的UTF-8
3.boolean:存儲一個布爾值,true或false
4.integer:整數可以是32位或64位,這取決于服務器
5.double:存儲浮點值
6.arrays:數組或列表,多個值存儲到一個鍵
7.object:用于嵌入式的文檔,即一個值為一個文檔
8.null:存儲null值
9.timestamp:時間戳
10.date:存儲當前日期或時間的UNIX時間格式
(其中:object id:每個文檔都有一個屬性,為_id,保證每個文檔的唯一性,可以自己去設置_id插入文檔,如果沒有提供,那么MongoDB為每個文檔提供了一個獨特的_id,類型為objectID是一個12字節的十六進制數,前4個字節為當前時間戳,接下來3個字節的機器ID,接下來的2個字節是MongoDB的服務進程id,最后3個字節是簡單的增量值)。
數據庫基本操作
1、數據庫切換
db:查看當前數據庫名稱
show dbs:查看所有數據庫名稱,列出所有在物理上存在的數據庫。
use 數據庫名稱:切換數據庫,如果數據庫不存在,則指向數據庫,但不創建,直到插入數據或創建集合時數據庫才被創建。
默認的數據庫為test,如果你沒有創建新的數據庫,集合將存放在test數據庫中
2、數據庫刪除
db.dropDatabase():刪除當前指向的數據庫,如果數據庫不存在,則什么也不做
3、操作集合
db.createCollection('數據庫名稱',{capped:true,size:尺寸,max:1000}):在mongodb數據庫中我們將類似于MySQL中的表的概念稱為集合,將集合中每一行的記錄稱為文檔,用此命令來創建集合,其中第二個參數可以不寫,草capped表示是否指定該集合的尺寸,size表示該集合的具體尺寸是多少,max可以指定最大的文檔個數。如果指定了集合的尺寸,我們可以想象其就像一個環形隊列,當集合空間用完后,再插入的文檔就會覆蓋最初始的頭部的文檔!
show collections:查看當前數據庫中所有的集合。
db.集合名稱.drop():刪除指定的集合
db.集合名稱.insert({}):相向集合中插入數據,如果不指定_id字段,數據庫會自動分配。
db.集合名稱.find({},{}):查詢集合中的文檔,第一個字典參數為查詢的條件,相當于MySQL中的where后面的條件,第二個字典參數為查詢的結果顯示哪些內容。均可為空或者不寫,等效于db.集合名稱.find(),默認查詢出所有符合條件的文檔。
db.集合名稱.update({},{},{}):更新集合中的文檔,第一個字典為要更新的文檔的條件,第二個字典為更新的內容,第三個字典為時候全部更新,默認只會更新查詢到的第一條文檔。
db.集合名稱.save({}):保存文檔,如果不指定_id字段或指定的_id字段在現有集合中沒有,則會進行插入,相當于insert,如果已經有了,相當于更新,會閥蓋之前的文檔中的所有字段。
db.集合名稱.remove({},{justOne:true或false}):刪除符合條件的文檔,默認為false即刪除全部
db.集合名稱.findOne({}):查詢出符合條件的第一條文檔。
比較運算符
‘:’等于,默認是等于判斷,沒有運算符
小于$lt? (less than)
小于或等于$lte (less than equal)
大于$gt?
大于或等于$gte (great than equal)
不等于$ne? (not equal)
邏輯運算符:,默認為與關系,$or為或關系
范圍運算符:$in和$nin,表示的是單個的值,而不是連續的范圍
正則表達式://或$regex
自定義查詢:查詢的條件可以是一個函數,且js中字符串的函數均可以使用。
limit和skip:limit指定讀取文檔的數量,skip指定跳過多少條文檔,可以和find()配合使用,limit和skip沒有先后順序。
投影:在查詢到的返回結果中,只選擇必要的字段,而不是選擇一個文檔的整個字段
排序:sort(),1為升序,-1為降序
統計個數:count()
消除重復:distinct()
數據庫高級操作
聚合
聚合操作aggregate類似于Linux和Unix中的管道命令‘|’,一般用于將當前命令的輸出結果作為下一個命令的輸入,如ps -aux | grep mongo,。在mongodb中,管道具有同樣的作用,文檔處理完畢后,通過管道進行下一次處理。
常用的管道如下:
$group:將集合中的文檔分組,可用于統計結果
$match:過濾數據,只輸出符合條件的文檔
$project:修改輸入文檔的結構,如重命名、增加、刪除字段、創建計算結果
$sort:將輸入文檔排序后輸出
$limit:限制聚合管道返回的文檔數
$skip:跳過指定數量的文檔,并返回余下的文檔
$unwind:將數組類型的字段進行拆分
常用表達式如下:
$sum:計算總和,$sum:1同count表示計數
$avg:計算平均值
$min:獲取最小值
$max:獲取最大值
$push:在結果文檔中插入值到一個數組中
$first:根據資源文檔的排序獲取第一個文檔數據
$last:根據資源文檔的排序獲取最后一個文檔數據
$group():分組
$match、$group、$project、$sort、$skip、$limit
$unwind:將文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值
我們可以看到,集合中有很多條記錄,但實際上只有最后一個記錄包含有size這個字段且其是一個數組,接下來根據$size進行拆分:
可以看到其他不包含size字段的文檔都丟失了,接下來拆分時再加上一個參數:
索引
索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數據時必須掃描集合中的每個文件并選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是非常低的,特別在處理大量的數據時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常致命的。索引是特殊的數據結構,索引存儲在一個易于遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構,其中存放的是集合中的部分字段和一些類似于地址一類的方便找到相應文檔的地址的東西。
db.集合.ensureIndex({"列":1}):創建索引,1表示索引按升序存儲,-1表示索引按降序方式存儲。
db.集合.getIndexes():查詢索引
db.集合.dropIndex({"列":1}):刪除索引
db.集合.ensureIndex({"列":1},{unique":true}):唯一索引
db.集合.find().explain('allPlansExecution'):查看查詢的詳細過程。
在mongodb的collections中有一個默認存在的以_id為索引的內置索引,此索引不需要手動創建即可獲取到:
db.集合.getIndexes():查詢索引
db.集合名稱.ensureIndex({'列':1或-1}):創建索引(1為升序排序,-1為降序排序)
看上這樣一個集合,我們在沒有手動創建索引的情況下,來看一下查詢age為num14的文檔的具體過程:
可以看到查詢過程并,沒有使用索引,且不得不對整個集合進行全盤掃描,一共查詢了12條文檔,查詢時間雖然幾乎是0,但是一旦數據量十分龐大,效率就十分不樂觀了。
下面我們一age為索引來創建一個唯一索引:
再來看一下搜索的過程:
可以看到在這樣的情況下,只查詢一條文檔就查詢到了所需的文檔,雖然查詢時間也是0,但數據量非常大時,和未建立索引的的查詢效率對比就十分明顯了。
db.集合名稱.dropIndex({'列:1或-1'}):刪除索引
索引限制:
1、額外開銷
每個索引占據一定的存儲空間,在進行插入,更新和刪除操作時也需要對索引進行操作。所以,如果你很少對集合進行讀取操作,建議不使用索引。
2、內存(RAM)使用
由于索引是存儲在內存(RAM)中,你應該確保該索引的大小不超過內存的限制。如果索引的大小大于內存的限制,MongoDB會刪除一些索引,這將導致性能下降。
3、查詢限制
索引不能被以下的查詢使用:
a、正則表達式及非操作符,如$nin, $not,等。
b、算術運算符,如$mod,等。
c、$where子句
4、索引鍵限制
從2.6版本開始,如果現有的索引字段的值超過索引鍵的限制,MongoDB中不會創建索引。
5、插入文檔超過索引鍵限制
如果文檔的索引字段值超過了索引鍵的限制,MongoDB不會將任何文檔轉換成索引的集合。與mongorestore和mongoimport工具類似。
6、最大范圍
a、集合中索引不能超過64個
b、索引名的長度不能超過128個字符
c、一個復合索引最多可以有31個字段
安全
為了更安全的訪問mongodb,需要訪問者提供用戶名和密碼,于是需要在mongodb中創建用戶,采用了角色-用戶-數據庫的安全管理方式。
在啟用安全驗證的情況下,需先修改配置文件,默認是不進行安全驗證的,執行如下操作:
sudo? vim /etc/mongodb.conf
常用系統角色如下:
root:只在admin數據庫中可用,超級賬號,超級權限
read:允許用戶讀取指定數據庫
readWrite:允許用戶讀寫指定數據庫
創建超級用戶:
超級用戶登錄:sudo mongo -u 'xxx' -p '******' --authenticationDatabase 'admin'
創建普通用戶:
普通用戶登錄:sudo mongo -u 'xxx' -p '******' --authenticationDatabase 'collection'
副本集
什么是復制
復制提供了數據的冗余備份,并在多個服務器上存儲數據副本,提高了數據的可用性,并可以保證數據的安全性,復制還允許從硬件故障和服務中斷中恢復數據。
為什么要復制
a、數據備份
b、數據災難恢復
c、讀寫分離
d、高(24* 7)數據可用性
d、無宕機維護
e、副本集對應用程序是透明
復制的工作原理
復制至少需要兩個節點A、B...,A是主節點,負責處理客戶端請求,其余的都是從節點,負責復制主節點上的數據。節點常見的搭配方式為:一主一從、一主多從,主節點記錄在其上的所有操作,從節點定期輪詢主節點獲取這些操作,然后對自己的數據副本執行這些操作,從而保證從節點的數據與主節點一致,主節點與從節點進行數據交互保障數據的一致性,只有主節點才能進行數據的增刪改操作,從節點只能進行查詢操作。
復制的特點
a、N個節點的集群
b、任何節點可作為主節點
c、所有寫入操作都在主節點上
d、自動故障轉移
e、自動恢復
模式一:主從復制
主從復制是MongoDB最常用的復制方式。這種方式非常靈活,可用于備份、故障恢復、讀擴展等。
最基本的設置方式就是建立一個主節點和一個或者多個從節點,每個從節點要知道主節點的地址。
運行mongod --master就啟動了主服務器,主服務器根據要求選取。
運行mongod --slave --source master_address則啟動了從服務器,其中master_address就是上面主節點的地址。
下面來模擬主從復制:
創建三個文件夾來模擬三臺服務器,在每個文件夾中分別包括一個db文件夾用來存放數據,log文件夾中的mongodb.log文件用來存放日志:
這樣就啟動了三臺mongodb服務器,并在啟動的時候確定了主機從機,在客戶端連接不同的服務器時,采用 sudo mongo --host 'xxxxx' -- port 'xxxxx'的方式進行連接,因為模擬是在同一臺機器上的,所以--host均為localhost,但在實際工作中,要根據具體情況而定。這樣就實現了主從復制。
主從復制存在一個缺陷就是,如果主機宕機了,從機不會自動選舉產生新的主機。
模式二:副本集
在主從復制模式中,我們知道主機宕機之后,從機不會通過自動選舉產生新的主機,而在設置副本集的模式中,則很好的解決了這一問題。在此模式中,啟動服務器時不設置主從機,而是為幾個服務器指定同一個副本集,第一個服務器在啟動之后需要進行初始化,指定這個服務器群中都有哪些成員,每個成員的權重分別是多少,權重最高的設置為primary主機,其余的設置為secondry從機,當主機宕機時,成員會自動感應,并自動選舉secondry中權重最高的為新的主機,假如宕機的主機又恢復正常,則這個主機就會重新稱為primary,其他成員仍然為secondry,并且會與從機中的數據保持一致。
模擬一下副本集:創建的目錄結構與主從復制相同,這里不再進行贅述。下面看一下具體操作:
第一臺服務器啟動之后的操作非常重要:
第一步:rs.slaveOk();
第二步:進行初始化:
第三步:查看狀態:rs.status()? (不是必須的)
其他服務器不需要再進行初始化,但同樣需要rs.slaveOk()等操作,與主從復制相同,只有primary可以進行增刪改操作,secondry只能進行查詢。
客戶端連接的方式相同,同樣采用sudo mongo -- host 'xxxx' --port 'xxxx'的方式
備份與恢復
備份:
語法:mongodump -h dbhost -d dbname -o dbdirectory
-h:服務器地址,也可以指定端口號
-d:需要備份的數據庫名稱
-o:備份的數據存放位置,此目錄中存放著備份出來的數據
例1
sudo mkdir test1bak
sudo mongodump -h127.0.0.1:27017 -d test1 -o ~/Desktop/test1bak
恢復
語法:mongorestore -h dbhost -d dbname --dir dbdirectory
-h:服務器地址
-d:需要恢復的數據庫實例
--dir:備份數據所在位置
例2
mongorestore -h 127.0.0.1:27017 -d test2 --dir ~/Desktop/test1bak/test1
mongodb與python進行交互
安裝pymongo包:sudo pip install pymongo
下面簡單實現一下增刪改查操作: