MongoDB Glossary
MongoDB 核心概念與術語參考。
RDBMS vs MongoDB
flowchart LR
subgraph RDBMS
subgraph SQL_Database[SQL Database]
subgraph Tables
subgraph Rows
subgraph Columns
end
end
end
end
end
subgraph MongoDB
subgraph NoSQL_Database[NoSQL Database]
subgraph Collection
subgraph Documents
subgraph Fields
end
end
end
end
end
Tables <-->|vs| Collection
Rows <-->|vs| Documents
Columns <-->|vs| Fields
| RDBMS | MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document |
| Column | Field |
| Index | Index |
| JOIN | $lookup / Embedded Document |
Schema Design Patterns
核心原則: 一起存取的資料應該一起儲存(Data that is accessed together should be stored together)
Inheritance Pattern
將不同類型但有共同屬性的資料存放在同一 Collection,透過 product_type 欄位區分:
classDiagram
class Books {
title
author
publisher
}
class eBook {
title
author
publisher
product_type: "ebook"
}
class printedBook {
title
author
publisher
product_type: "printed"
}
class audioBook {
title
author
publisher
product_type: "audio"
}
Books <|-- eBook
Books <|-- printedBook
Books <|-- audioBook
其他常見 Pattern
| Pattern | 說明 | 適用場景 |
|---|---|---|
| Computed Pattern | 預先計算並儲存結果 | 頻繁讀取的聚合結果 |
| Approximation Pattern | 儲存近似值而非精確值 | 計數器、統計資料 |
| Extended Reference Pattern | 嵌入常用欄位的副本 | 減少 $lookup 查詢 |
| Schema Versioning Pattern | 文件包含 schema 版本 | 漸進式 schema 演進 |
Document Design 實例:遊戲角色系統
透過 RPG 遊戲角色系統,比較 RDBMS 與 MongoDB 的設計差異。
RDBMS 正規化設計
erDiagram
players ||--o{ characters : has
characters ||--o{ inventory : has
inventory }o--|| items : references
characters ||--o{ character_skills : has
character_skills }o--|| skills : references
players {
int player_id PK
string username
string email
datetime created_at
}
characters {
int character_id PK
int player_id FK
string name
string class
int level
int hp
int mp
}
items {
int item_id PK
string name
string type
int base_damage
}
inventory {
int inventory_id PK
int character_id FK
int item_id FK
int quantity
}
skills {
int skill_id PK
string name
int mana_cost
}
character_skills {
int character_id FK
int skill_id FK
int skill_level
}
特點:
- 6 個表,透過 Foreign Key 關聯
- 查詢角色完整資訊需要多次 JOIN
- 修改 item 基本資料只需更新一處
MongoDB 文件設計
{
"_id": ObjectId("..."),
"username": "player123",
"email": "player@example.com",
"created_at": ISODate("2024-01-15"),
"characters": [
{
"character_id": "char_001",
"name": "DragonSlayer",
"class": "Warrior",
"level": 42,
"stats": {
"hp": 1500,
"mp": 200,
"strength": 85,
"agility": 45
},
"inventory": [
{
"item_id": "sword_001",
"name": "Flame Sword",
"type": "weapon",
"damage": 150,
"quantity": 1,
"equipped": true
},
{
"item_id": "potion_001",
"name": "Health Potion",
"type": "consumable",
"effect": "+500 HP",
"quantity": 10
}
],
"skills": [
{
"skill_id": "skill_001",
"name": "Flame Strike",
"level": 5,
"mana_cost": 50
}
]
}
]
}特點:
- 1 個 Document 包含所有相關資料
- 查詢角色完整資訊只需一次讀取
- 適合「讀取時需要完整資料」的場景
設計比較
| 面向 | RDBMS | MongoDB |
|---|---|---|
| 資料結構 | 多表 + Foreign Key | 單一 Document 嵌入 |
| 查詢完整角色 | 多次 JOIN | 單次讀取 |
| 更新物品基本資料 | 更新一處即可 | 需更新所有嵌入的副本 |
| 新增欄位 | 需 ALTER TABLE | 直接新增,無需 schema 變更 |
| 交易一致性 | 原生 ACID | 單文件原子性,多文件需交易 |
| 適用場景 | 資料關聯複雜、需頻繁更新 | 讀取為主、資料常一起存取 |
設計決策指南
何時使用嵌入(Embedding):
- 資料通常一起讀取
- 子資料生命週期依賴父資料
- 子資料數量有限且不會無限增長
何時使用引用(Reference):
- 子資料獨立於父資料存在
- 子資料數量可能很大
- 需要獨立查詢子資料
Transaction
MongoDB 支援多文件 ACID 交易(4.0+)。
Read Concern
控制讀取操作返回的資料一致性層級:
| Level | 說明 |
|---|---|
local | 返回本地最新資料(預設) |
available | 類似 local,用於 sharded cluster |
majority | 返回已被多數節點確認的資料 |
linearizable | 返回反映所有成功寫入的資料 |
snapshot | 返回交易開始時的快照 |
Write Concern
控制寫入操作的確認層級:
| Level | 說明 |
|---|---|
w: 1 | 主節點確認(預設) |
w: "majority" | 多數節點確認 |
w: <number> | 指定數量節點確認 |
j: true | 寫入 journal 後確認 |
Read Preference
控制從哪個節點讀取資料:
| Mode | 說明 |
|---|---|
primary | 只從主節點讀取(預設) |
primaryPreferred | 優先主節點,不可用時讀取次要節點 |
secondary | 只從次要節點讀取 |
secondaryPreferred | 優先次要節點 |
nearest | 從網路延遲最低的節點讀取 |
Replica Set
MongoDB 的高可用性機制,由多個 mongod 實例組成。
節點類型
| 類型 | 說明 |
|---|---|
| Primary | 接收所有寫入操作 |
| Secondary | 複製 Primary 的資料,可處理讀取 |
| Arbiter | 僅參與投票,不儲存資料 |
Explain(執行計畫分析)
SQL 資料庫的執行計劃分析,請參考 SQL Explain
使用 explain() 分析查詢效能:
db.collection.find({ ... }).explain("executionStats")queryPlanner 欄位說明
| 欄位 | 說明 |
|---|---|
namespace | 查詢的集合 |
indexFilterSet | 是否使用索引 |
parsedQuery | 解析後的查詢條件 |
winningPlan | 最佳執行計劃 |
rejectedPlans | 被拒絕的執行計劃 |
executionStats 欄位說明
| 欄位 | 說明 |
|---|---|
executionSuccess | 是否執行成功 |
nReturned | 返回的文件數 |
executionTimeMillis | 執行時間(毫秒) |
totalKeysExamined | 索引掃描次數 |
totalDocsExamined | 文件掃描次數 |
Stage 類型
| Stage | 說明 | 效能 |
|---|---|---|
COLLSCAN | 全表掃描 | ⚠️ 避免 |
IXSCAN | 索引掃描 | ✅ 建議 |
FETCH | 根據索引檢索文件 | ✅ 正常 |
IDHACK | 對 _id 查詢的優化 | ✅ 最佳 |
SORT | 記憶體排序 | ⚠️ 考慮加索引 |
LIMIT | 限制返回數量 | ✅ 正常 |
SKIP | 跳過文件 | ⚠️ 大量 skip 效能差 |
SHARD_MERGE | 合併分片結果 | ✅ 正常 |
COUNT_SCAN | 使用索引計數 | ✅ 建議 |
COUNTSCAN | 不使用索引計數 | ⚠️ 避免 |
TEXT | 全文索引查詢 | ✅ 正常 |
PROJECTION | 欄位投影 | ✅ 正常 |
應避免的 Stage
以下 Stage 出現時應考慮優化:
- COLLSCAN - 全表掃描,應建立索引
- SORT - 記憶體排序,應建立複合索引
- SUBPLA - 未使用索引的
$or查詢 - COUNTSCAN - 不使用索引的 count
- 大量 SKIP - 考慮使用 range query 替代
Explain 輸出範例
{
"explainVersion": "1",
"stages": [
{
"$cursor": {
"queryPlanner": {
"namespace": "demo.sop",
"parsedQuery": { "_id": { "$eq": "951753" } },
"winningPlan": { "stage": "IDHACK" }
},
"executionStats": {
"executionSuccess": true,
"nReturned": 1,
"executionTimeMillis": 0,
"totalKeysExamined": 1,
"totalDocsExamined": 1
}
}
},
{
"$lookup": {
"from": "sop_acl",
"as": "acl_data",
"localField": "_id",
"foreignField": "sop_id",
"totalDocsExamined": 4,
"collectionScans": 1,
"indexesUsed": []
}
}
]
}上例中 $lookup 階段的 collectionScans: 1 表示對 sop_acl 進行了全表掃描,應考慮在 sop_id 欄位建立索引。
Aggregation Pipeline
聚合管線是 MongoDB 進行資料分析的核心功能,類似 SQL 的 GROUP BY。
常用階段
詳見 MongoDB CLI - Aggregation Pipeline
MongoDB Compass
MongoDB 官方的 GUI 工具,提供:
- 視覺化查詢建構
- Schema 分析
- 效能監控
- 索引管理
- Aggregation Pipeline 建構器