MongoDB安裝與快速入門
一、前言
MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫,介于關(guān)系型數(shù)據(jù)庫與非關(guān)系型數(shù)據(jù)庫之間,是非關(guān)系數(shù)據(jù)庫中功能最豐富,最像關(guān)系型數(shù)據(jù)庫的。它支持的結(jié)構(gòu)非常松散,是類似json的bson格式,因此可以存儲比較復雜的數(shù)據(jù)類型。MongoDB最大的特點是它支持的查詢非常強大,其語法有點類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實現(xiàn)類似關(guān)系型數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。
- Document(文檔): 是MongoDB中數(shù)據(jù)的基本單元,它非常類似于關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)行。
- Collection(集合): 可以看作是一個擁有動態(tài)模式的表。
- MongoDB的一個實例可以擁有多個相互獨立的數(shù)據(jù)庫(database), 每一個數(shù)據(jù)庫都擁有自己的集合。
- 每個文檔都有一個特殊的鍵`_id`, 這個鍵在文檔所屬的集合中是唯一的。
1.1. MongoDB
- MongoDB是一個基于分布式文件存儲的NoSQL數(shù)據(jù)庫
- 由c++語言編寫,運行穩(wěn)定,性能高
- 旨在為web應(yīng)用提供可擴展的高性能的數(shù)據(jù)存儲解決方案
1.2. MongoDB特點
- 模式自由 :可以把不同結(jié)構(gòu)的文檔存儲在同一個數(shù)據(jù)庫里
- 面向集合的存儲:適合存儲 JSON風格文件的形式
- 完整的索引支持:對任何屬性可索引
- 復制和高可用性:支持服務(wù)器之間的數(shù)據(jù)復制,支持主-從模式及服務(wù)器之間的相互復制。復制的主要目的是提供冗余及自動故障轉(zhuǎn)移
- 自動分片:支持云級別的伸縮性:自動分片功能支持水平的數(shù)據(jù)庫集群,可動態(tài)添加額外的機器
- 豐富的查詢:支持豐富的查詢表達方式,查詢指令使用JSON形式的標記,可輕易查詢文檔中的內(nèi)嵌的對象及數(shù)組
- 快速就地更新:查詢優(yōu)化器會分析查詢表達式,并生成一個高效的查詢計劃
- 高效的傳統(tǒng)存儲方式:支持二進制數(shù)據(jù)及大型對象(如照片或圖片)
1.3.MongoDB與SQL名詞解釋與對比
MongoDB術(shù)語與關(guān)系型SQL對比
- document: 文檔,就是一個對象,由鍵值對構(gòu)成,是json的擴展bson形式
{'name':'楊過', 'gender':'男'}
- collection: 集合,類似于關(guān)系型數(shù)據(jù)庫中的表,存儲多個文檔,結(jié)構(gòu)不固定
{'name':'風清揚', 'age': 55, 'gender': '男'}
{'name':'令狐沖', 'age': 32, 'gender': '男', 'partner':'小龍女'}
{'name':'喬峰', 'age':40, 'gender': '男', 'kongfu':'響龍十八掌'}
- database: 數(shù)據(jù)庫,是一個集合的物理容器,一個數(shù)據(jù)庫中可以包含多個集合。
二、文檔
文檔是MongoDB中的核心概念。文檔就是鍵值對的一個有序集。每種編程語言表示文檔的方法不太一樣,但是大多數(shù)編程語言都有一些通用的數(shù)據(jù)結(jié)構(gòu),比如映射map、散列hash、字典等。例如:
{"name": "風清揚", "age": 54, "gender":"男"}
MongoDB不但區(qū)分類型,還區(qū)分大小寫,比如下面的兩個文檔是不同的:
# 區(qū)分大小寫
{"name": "terminator"}
{"Name": "terminator"}
# 區(qū)分類型
{"age": "54"}
{"age": 54}
MongoDB中的鍵不能重復,例如下面的文檔是非法的:
{"name":"zhangsanfeng", "name":"zhangwuji", "age":56}
MongoDB中鍵/值是有順序的,例如,下面的兩個文檔也是不同的:
{"name":"linqingxia", "age": 52}
{"age": 52, "name":"linqingxia"}
三、集合
集合就是有一組文檔組成,相當于關(guān)系型數(shù)據(jù)庫中表的概念。而文檔就相當于關(guān)系型數(shù)據(jù)庫表中的一行記錄。
3.1.動態(tài)模式
集合是動態(tài)模式的,這就意味著集合里的文檔可以是各式各樣的,不需要每個文檔具有相同的鍵。例如:
{"name":"張無忌", "kongfu":"九陽神功", "age": 25}
{"department":"賬務(wù)部"}
需要注意的是,上面的文檔有不同值的類型、鍵的個數(shù)和鍵的名稱完全不相同。因為集合里面可以放置任何文檔,隨之而來的一個問題是:還有必要使用多個集合嗎?這里有幾個重要的原因:
- 如果把不同文檔不加以任何區(qū)分放在同一個集合里,無論對開發(fā)者還是管理者來說都非常困難。
- 在一個集合里查詢特定類型的文檔在速度上將消耗很大資源,分成多個集合后可以提高查詢效率。
- 把同種類型的文檔放在一個集合里,數(shù)據(jù)會更加集中。
- 創(chuàng)建索引時,需要使用文檔的附加結(jié)構(gòu)(特別是創(chuàng)建唯一索引時)。索引是按照集合來定義的。在一個集合中放入一種類型的文檔,可以更加有效地對集合進行索引與操作。
3.2. 集合的命名規(guī)則
如同關(guān)系型數(shù)據(jù)庫中的表一樣,集合使用名稱進行標識。集合名稱可以是滿足下面條件的任意UTF-8字符串。
- 集合名稱不能是空的字符串"";
- - 集合名稱不能包含字符(空字符),這個字符表示集合名的結(jié)束。
- - 集合名不能以"system."開頭,這是為系統(tǒng)集合保留的前綴。例如:system.users這個集合保存著用戶的基本信息。
- - 用戶創(chuàng)建的集合最好不要在集合名稱中包含"$"符號。因為某些系統(tǒng)生成的集合中包含"$"符號。
3.2.1.子集合
組織集合的一種慣例是使用"."來分隔不同命名空間的子集合。例如,一個具有博客功能的應(yīng)用可能包含兩個集合,分別是blog.posts和blog.authors。這樣劃分是為了使組織結(jié)構(gòu)更加清晰,這里的blog集合(這個集合甚至不需要存在)跟它的子集合沒有任何關(guān)系。
雖然子集合沒有任何特別的屬性,但它們非常有用,因而很多的MongoDB工具都使用子集合。
- GridFS(一種用于存儲大文件的協(xié)議)使用子集合來存儲文件的元數(shù)據(jù),這樣可以與文件內(nèi)容很好地隔離開來。
- 大多數(shù)MongoDB數(shù)據(jù)庫的驅(qū)動程序提供了一些語法糖,用于訪問指定集合的子集合。例如MongoDB數(shù)據(jù)庫的shell中,db.blog代表blog集合,而db.blog.posts代表blog.posts子集合。
在MongoDB中,使用子集合來組織數(shù)據(jù)非常高效,值得推薦使用子集合。
四、數(shù)據(jù)庫
在MongoDB中,多個文檔組成集合,而多個集合則可以組成數(shù)據(jù)庫。一個MongoDB實例可以承載多個數(shù)據(jù)庫,每個數(shù)據(jù)庫可以包含0個或多個集合。每個數(shù)據(jù)庫擁有獨立的權(quán)限,即便是在磁盤上,不同的數(shù)據(jù)庫在物理上也存儲在不同的文件中。
和關(guān)系型數(shù)據(jù)庫一樣,通過名稱來標識數(shù)據(jù)庫名,數(shù)據(jù)庫的命名可以是滿足下面條件的任意UTF-8字符串:
- 不能是空字符串”“
- 不得含有(/,\, ",*,<,>,:,|,?,$)等特殊字符。基本上使用ASCII中的字母和數(shù)字。
- 數(shù)據(jù)庫名稱區(qū)分大小寫,一般來說,數(shù)據(jù)庫名全用小寫名稱。
- 數(shù)據(jù)庫名稱最多64個字節(jié)。
數(shù)據(jù)庫最終對應(yīng)系統(tǒng)中的文件,而數(shù)據(jù)庫名稱就是文件的名稱,這也是數(shù)據(jù)庫名稱命名需要這么多限制的根本原因。
另外,MongoDB保留了一些數(shù)據(jù)庫名稱,這些數(shù)據(jù)庫有特殊的用途:
- admin: 從身份驗證的角度來看,這是一個`root`數(shù)據(jù)庫。如果將一個用戶添加到admin數(shù)據(jù)庫,這個用戶將自動獲得所有數(shù)據(jù)庫的權(quán)限。另外,一些特定服務(wù)器端的命令也只能從admin數(shù)據(jù)庫運行,如列出所有數(shù)據(jù)庫或關(guān)閉服務(wù)器等。
- local: 這個數(shù)據(jù)庫永遠都不可以復制,且一臺服務(wù)器上的所有本地集合都可以存儲在這個數(shù)據(jù)庫中。
- config: MongoDB用于分片設(shè)置時,分片信息會存儲在config數(shù)據(jù)庫中。
五、MongoDB的安裝與配置
在Ubuntu下MongoDB的安裝非常簡單,無需下載源文件,可以直接使用`apt-get`命令進行安裝。
- 安裝mongodb命令
(base) hadoop@node1:~$ sudo apt-get install mongodb
MongoDB shell
- 查看mongodb版本命令
# 查看mongodb的版本信息
(base) hadoop@node1:~$ mongo -version
MongoDB版本
- 查看mongodb啟動狀態(tài)命令
# 查看mongodb啟動狀態(tài)
(base) hadoop@node1:~$ sudo systemctl status mongodb
MongoDB啟動狀態(tài)
- 關(guān)閉mongodb命令
(base) hadoop@node1:~$ sudo systemctl stop mongodb
- 啟動mongodb命令
(base) hadoop@node1:~$ sudo systemctl start mongodb
默認情況下MongoDB是隨ubuntu啟動的,可以通過以下命令查看
(base) hadoop@node1:~$ pgrep mongo -l
pgrep mongo -l
- 卸載MongoDB命令
$ sudo apt-get --purge remove mongodb mongodb-clients mongodb-server
六、MongoDB Shell簡介
MongoDB自帶了JAVAScript shell, 可以在shell中使用命令行與MongoDB實時交互。shell非常有用,通過它可以執(zhí)行某些對MongoDB的管理操作,檢查運行的實例等。
運行`mongo`啟用shell:
mongo命令啟動shell
啟動shell時,shell將自動連接MongoDB服務(wù)器,在啟動MongoDB shell前,確保mongod服務(wù)已啟動。shell是一個功能完備的JavaScript解釋器,可以運行任意的JavaScript程序,例如:
> a = 100
100
> a/5
20
> Math.sin(Math.PI/2)
1
> new Date()
ISODate("2020-07-30T06:15:30.924Z")
> "Hi MongoDB, Hi Python".replace("Python","Mongo");
Hi MongoDB, Hi Mongo
> function factorial(n) {
... if(n<=1) return 1;
... return n*factorial(n-1);
... }
> factorial(5)
120
6.2.MongoDB客戶端
MongoDB shell可以運行任意的JavaScript腳本聽上去很酷,不過它的真正強大之處在于,它是一個獨立的MongoDB客戶端,在shell啟動時,它會連接到MongoDB服務(wù)器的`test`數(shù)據(jù)庫,并將數(shù)據(jù)庫連接賦值給全局變量db。這個全局變量是通過shell訪問MongoDB的主要入口點。
例如下面的命令:
# 查看db當前指向哪個數(shù)據(jù)庫
> db
test
# 列出當前MongoDB中有哪些數(shù)據(jù)庫
> show dbs
admin 0.000GB
config 0.000GB
crm 0.000GB
local 0.000GB
# 切換數(shù)據(jù)庫
> use crm
switched to db crm
6.3.shell中的基本操作
在shell中查看或操作數(shù)據(jù)會用到4個基本操作:創(chuàng)建、讀取、更新和刪除。即通常所說的`CRUD`。
- 創(chuàng)建
`insert`可以將一個文檔添加到集合中。
> use movie
switched to db movie
> actor = {"name":"喬峰","age":40, "movie":"天龍八部","author":"金庸","kongfu":"響龍十八掌","department":"丐幫"}
{
"name" : "喬峰",
"age" : 40,
"movie" : "天龍八部",
"author" : "金庸",
"kongfu" : "響龍十八掌",
"department" : "丐幫"
}
> db.movie.actors.insert(actor)
WriteResult({ "nInserted" : 1 })
> db.movie.actors.find()
{ "_id" : ObjectId("5f226c49a20e34cfb8a8ab33"), "name" : "喬峰", "age" : 40, "movie" : "天龍八部", "author" : "金庸", "kongfu" : "響龍十八掌", "department" : "丐幫" }
> actor = {"name":"段譽","age":34, "movie":"天龍八部","author":"金庸","kongfu":"六脈神劍","department":"大理國"}
{
"name" : "段譽",
"age" : 34,
"movie" : "天龍八部",
"author" : "金庸",
"kongfu" : "六脈神劍",
"department" : "大理國"
}
> db.movie.actors.insert(actor)
WriteResult({ "nInserted" : 1 })
> db.movie.actors.find()
{ "_id" : ObjectId("5f226c49a20e34cfb8a8ab33"), "name" : "喬峰", "age" : 40, "movie" : "天龍八部", "author" : "金庸", "kongfu" : "響龍十八掌", "department" : "丐幫" }
{ "_id" : ObjectId("5f226d25a20e34cfb8a8ab34"), "name" : "段譽", "age" : 34, "movie" : "天龍八部", "author" : "金庸", "kongfu" : "六脈神劍", "department" : "大理國" }
>
- 讀取
find()和fineOne()都可以用于查詢集合中的文檔。若只需要查看一個文檔使用findOne()。
> db.movie.actors.findOne()
{
"_id" : ObjectId("5f226c49a20e34cfb8a8ab33"),
"name" : "喬峰",
"age" : 40,
"movie" : "天龍八部",
"author" : "金庸",
"kongfu" : "響龍十八掌",
"department" : "丐幫"
}
- 更新
可以使用update更新文檔,update至少需要兩個參數(shù):第一個是限定條件(限定集合中待更新的文檔),第二個是新的文檔。
> actor.comments = ['很厲害','妹子好多啊']
[ "很厲害", "妹子好多啊" ]
> db.movie.actors.update({"name":"段譽"}, actor)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.movie.actors.find()
{ "_id" : ObjectId("5f226c49a20e34cfb8a8ab33"), "name" : "喬峰", "age" : 40, "movie" : "天龍八部", "author" : "金庸", "kongfu" : "響龍十八掌", "department" : "丐幫" }
{ "_id" : ObjectId("5f226d25a20e34cfb8a8ab34"), "name" : "段譽", "age" : 34, "movie" : "天龍八部", "author" : "金庸", "kongfu" : "六脈神劍", "department" : "大理國", "comments" : [ "很厲害", "妹子好多啊" ] }
>
- 刪除
使用remove方法可以將文檔從數(shù)據(jù)庫中永久刪除。如果沒有任何參數(shù),它會將集合內(nèi)的所有文檔全部刪除。它也可以接受一個作為限定條件的文檔作為參數(shù)。例如:
> db.movie.actors.remove({"name":"段譽"})
后記
由于MongoDB的內(nèi)容比較多,接下來會分幾篇文章講解MongoDB的數(shù)據(jù)類型、查詢操作等內(nèi)容。