MongoDB Note 01
基礎概念簡介
前言
傳統的資料庫使用的是關聯式資料庫管理系統(Relational Database Management System/RDBMS)
,需要在關聯式資料庫中事先定義好Schema(綱要)
;也就是每張Table(資料表)
中包含哪一些Column(欄位)
,並且要確保後續新增儲存的Row(資料)
都要遵循schema的定義。
這邊舉個例子,如果想要在RDBMS中記錄會員的資訊,如果最初定義Product 資料表
的schema中有姓名、職業、身高、體重四個欄位,則該資料表中的每一筆資料都必須要有這四個欄位,結果資料表快建完了才發現忘記加上血型這個欄位,又或者希望幫其中一個會員紀錄上興趣,這種狀況在關聯式資料庫中,因為要遵守schema的定義,所以需要更動schema,在欄位上新增血型、興趣欄位,再來寫一個script幫現有所有的會員都加上興趣(若無可填上空值)。
比起上述的情況,對於MongoDB來說,因為它被設計為一種以document
為主的database,所以可以直接將興趣欄位直接加入屬於這個會員的資料內即可。除了可以很容易的增加欄位外,MongoDB還能透過Sharding
功能,輕易地水平擴展整體的資料庫大小。
MongoDB的層級架構
MongoDB的層級從大到小分別是Database
、Collection
和Document
,下面這張圖對應了MongoDB和傳統關聯式資料庫SQLDatabase
的對應關係:
SQL | MongoDB | 說明 |
---|---|---|
Database | Database | 資料庫 |
Table | Collection | 資料表/集合 |
Row | Document | 一筆數據紀錄/文檔 |
Column | Field | 數據欄位/域 |
Index | Index | 索引 |
Table Joins | 合併資料表/MongoDB沒有Join | |
Primary Key | Primary Key | 主鍵 |
Database
一個MongoDB伺服器中可以有多個獨立的Database
,每一個都有自己的collection和權限,在實際上的應用中,不同服務或是應用的資料會放在不同的database中。
例如有一家公司同時有A和B服務,兩者的資料是不相通的,那就可以直接在MongoDB中建立兩個database,分別存放兩服務所需要儲存的資料。
資料庫的名字在MongoDB中有著一些限制:
- 不能是空字串
- 不可以含有' '(空格)、.(點)、$(錢字符)、/(斜線)、\(反斜線)和\0(空字符)
- 應全為小寫
- 最多64個字元
此外,有一些database的名稱是建立時就預設存在的,可以直接連結進行查看:
- admin
MongoDB會將所有使用者的資訊儲存在這個database(名稱、密碼和使用者的驗證資料庫),如果要建立個別database的使用者,在個別的database中建立即可,但如果要跨database使用,則需要在這個資料庫中建立,會自動繼承到其他database,關於管理使用者的方法會在額外發一篇介紹。 - local
這個database永遠不會被複製,用來儲存這台機器的檔案和資訊,不會因為建立💡replica set(建立副本,預防MongoDB掛掉而導致服務掛掉)複製這個database的資料。 - config
主要存放Sharding
相關的資料,在3.6版本以後,會儲存standalone或是replication資料,也有跟transaction相關的資料,但是禁止去針對這個database進行修改或刪除,僅可以查看。
當MongoDB使用Sharding
時,config database會在內部使用,用於保存sharding的相關資訊。
建立database的方法很簡單,直接使用use
即可切換到指定的database,如果在MongoDB中沒有該database則會直接建立一個新的:
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use testDataset
switched to db testDataset
Collection
Collection
相當於關聯式資料庫的 Table的概念,主要差別在它存放的是document而非固定大小、格式的record,通常一個 databse 中會有數個 collection。
以database上的例子來說如果服務 A為一個銷售資料庫,可能會想要分別記錄「購買人資訊」、「製造商資訊」、「販售地點」...等等,因此可以在「產品 A 的 database」 中分別開設對應的 collection。
同時因為MongoDB沒有固定的結構,所以還可以針對特定的資料設計不同的結構,但同時都是屬於同一個collection。
例如以「購買人資訊」為例,可以只針對特定的user增加興趣的欄位,而其他的user則完全不受影響:
{
"name": 'Stank',
"job": 'software engineer',
"bloodType": 'A'
}
{
"name": 'Augustus',
"job": 'software engineer',
"bloodType": 'O',
"hobbies": ['sleeping', 'computer game', 'guitar'],
}
Document
Document
就是一筆資料,概念好比關聯式資料庫的Row。通常一個collection中會有數筆document。也因此我們稱MongoDB是document database
。
例如在「購買人資訊」的collection中,真正的一筆「購買人資訊」就是一個document。
以下是Document的例子,可以看到長的跟JSON一樣,由多組的key-value組成,不過在MongoDB中是使用field這個名稱:
{
"name": "Augustus", <----field:value
"age": 26, <----field:value
"status": "S", <----field:value
"groups": ["MongoDB", "GitLab"] <----field:value
}
MongoDB儲存格式 (BSON)
MongoDB每筆document都是像JSON格式的key-value組合,但實際上MongoDB在儲存資料的格式是BSON
(Binary JSON,JSON二進位表示形式),使用BSON的優點在於在空間上儲存較有效率,BSON支援的格式可以參考官網,這裡介紹一些比較特別的格式:
- binData
儲存二進制的資料(binary data)。 - timestamp & date
timestamp和date一樣是儲存時間的資料,但是date在跨時區的時候會有需要轉換時區的問題產生。 - object
可以在這個欄位中插入document,可以想像成文件中的子文件,如下範例的livein
欄位:
{
"name": 'Augustus',
"job": 'software engineer',
"bloodType": 'O',
"hobbies": ['sleeping', 'computer game', 'guitar'],
"livein":
{
"contry": 'Taiwan',
"city": 'Taipei'
}
}
- regex
用來儲存正則表達式。 - javascript
用來儲存javascript
語法。 - objectId
會在文章下面提到。
objectId
MongoDB的核心,可以透過這個id直接處理document,以下是objectId的幾個特性:
- 預設每一個文件都有的欄位(連object型態的資料都會有)
- 如果沒有設定,會自動產生這個欄位
- 每一個文件的唯一位置
- 系統預設的single index key
- collection層級的唯一值
- 資料行別為
ObjectId
以下是一個objectId的例子:
db.costumer.insertOne({ ... })
db.costumer.find()
{
"_id" : ObjectId("62d511895ddbc92df38d37e3"),
"name": 'Augustus',
"job": 'software engineer',
"bloodType": 'O',
"hobbies": ['sleeping', 'computer game', 'guitar'],
"livein":
{
"contry": 'Taiwan',
"city": 'Taipei'
}
}
系統如何生成objectId的相關文檔在這可以看到,另外objectId也可以自行定義,其他型別也可以拿來做為_id,但是需要確保_id在collection層級上的唯一性。
MongoDB優缺點比較
優點 | 缺點 |
---|---|
靈活的數據模型 | 需要更多的儲存空間 |
大部分可工作的數據儲存在RAM | RAM的使用會爆高 |
可水平擴展 (Sharding支援20PB) | 弱一致性 (最終一致),沒有💡ACID保證 |
沒有Triger | |
文檔=物件,不需要ORM(物件關係對映) | 重複的數據 |
索引(index) | 索引(index) |
不支援Join |
MongoDB實務層面上的問題
在使用MongoDB之前有查詢到MongoDB在實際使用上的一些問題:
- Aggregation查詢在橫跨多個Database、多個Collection時會變慢很多
需要有設計良好的Database和Collection才能確保擁有快速的查詢速度 - 後期效能問題:
百G以上的資料,需要有良好的index設計來提速
ex.資料庫內有十萬條6000字文本後,查詢速度降低
結論
MongoDB強勢的地方在於儲存資料的格式彈性,由於屬於NoSQL不需要定義Schema,可以輕易的新增、修改資料,對於剛開始使用資料庫,資料的格式還沒定下來的應用十分友善,在效能方面也是相當快速,又因為可以快速的水平擴張,在大數據的應用上也是相當方便。