為什麼需要 NoSQL?
SQL 資料庫非常強大,但在某些場景下會顯得笨重。最典型的例子是「多型態資料」—— 每筆資料的欄位數量和型別都不一樣,用固定的 Table Schema 來應對,往往是這樣的結果:
另一個典型場景是電商商品目錄:書有 ISBN、頁數;電子產品有電壓規格、處理器型號; 衣服有尺寸、顏色、材質。這些屬性之間幾乎沒有共同欄位。
NoSQL 不是「比 SQL 更好」
NoSQL(Not Only SQL)的設計初衷是解決特定問題:彈性 Schema、水平擴展、非結構化資料。 它犧牲了 SQL 的強一致性和複雜查詢能力,換取了靈活性和擴展性。 理解這個取捨,才是選型的起點。
MongoDB 基本概念
如果你有 SQL 背景,理解 MongoDB 最快的方式就是對照術語。 概念是相通的,只是換了一套命名邏輯。
SQL vs MongoDB 術語對照
| SQL | MongoDB | 說明 |
|---|---|---|
| Database | Database | 相同概念,一個 MongoDB 實例可有多個 DB |
| Table | Collection | 一組 document 的集合,不強制統一 Schema |
| Row | Document | BSON 格式(類 JSON),可嵌套物件與陣列 |
| Column | Field | Document 內的鍵值對 |
| PRIMARY KEY | _id(ObjectId) | 自動生成 12 bytes ID,內含時間戳 |
| JOIN | $lookup(Aggregation) | 效能不如 SQL JOIN,Schema 設計應避免過度依賴 |
| INDEX | Index | 支援單欄位、複合、TTL、全文、地理空間索引 |
BSON 型別:MongoDB 的 JSON 超集
MongoDB 在硬碟與網路傳輸中用 BSON(Binary JSON)格式,比純 JSON 支援更多型別:
ObjectId
12 bytes = 4 bytes 時間戳 + 5 bytes 機器識別 + 3 bytes 計數器。可從 _id 直接取得文件建立時間,不需額外 createdAt 欄位。
Date(ISODate)
儲存為 UTC 毫秒時間戳,查詢時可用 $gte / $lte 做時間範圍篩選,避免用字串儲存日期。
NumberInt / NumberLong / Decimal128
區分 32-bit 整數、64-bit 整數和高精度小數(金融計算用 Decimal128 避免浮點誤差)。
Binary(BinData)
儲存二進位資料,常用於存放檔案 hash、加密資料或小型縮圖(大檔案建議用 GridFS 或外部儲存)。
CRUD 操作 — Mongoose + Node.js
雖然 MongoDB 本身沒有強制 Schema,但在 Node.js 開發中我們通常使用 Mongoose——它在 MongoDB 之上加了 Schema 定義、型別驗證、 Middleware(Hooks)和方便的 Query API。
Aggregation Pipeline — MongoDB 的 GROUP BY
Aggregation Pipeline 是 MongoDB 最強大也最難的功能,等同於 SQL 的GROUP BY + HAVING + ORDER BY組合。資料流過一個個 Stage,每個 Stage 對資料做轉換,前一個 Stage 的輸出是下一個 Stage 的輸入。
Pipeline 概念示意
Schema 設計原則 — 最大的誤區
最常見的 NoSQL 誤區
很多人從 SQL 轉過來,直覺是「把每個實體拆成獨立 Collection,再用 $lookup JOIN 起來」。 但 MongoDB 的 $lookup 沒有 SQL JOIN 的效能優化,過度引用反而比嵌入慢 10 倍以上。 MongoDB Schema 的設計原則應該以「查詢模式」為起點,而不是以「資料結構」為起點。
嵌入(Embed)vs 引用(Reference)
選擇嵌入(Embed)的情況
- ✓「一對少」關聯(文章對評論,通常幾十則)
- ✓子文件不需要單獨查詢或列表顯示
- ✓子文件資料和父文件一起讀取
- ✓子文件總大小不會超過幾 MB
- ✓子文件不會被多個父文件共用
選擇引用(Reference)的情況
- ✓「一對多/很多」關聯(用戶對訂單,可能幾萬筆)
- ✓子文件需要單獨查詢(例:用戶資料頁)
- ✓子文件被多個父文件共用
- ✓子文件需要頻繁更新(不想重複修改多個地方)
- ✓子文件數量不可預測,可能無限增長
實務決策流程
- 先問:「最常見的查詢是什麼?」 — 以查詢效率為設計起點
- 資料是否需要「單獨存在」?(可以單獨被搜尋、更新、刪除?)→ 引用
- 資料是否「幾乎只在父文件脈絡下出現」?→ 嵌入
- 資料量是否可能無限增長?→ 引用(避免 document 超過 16MB 上限)
- 在不確定時:先嵌入,性能問題出現後再拆分
SQL vs NoSQL — 什麼時候選哪個
這是最常被問到的問題。答案不是「哪個更好」,而是「哪個更適合你的場景」。 大型系統(Twitter、Airbnb、Shopify)往往兩個都用:SQL 管核心業務資料, MongoDB 管用戶行為、內容、IoT 資料。
選型決策表
| 考量因素 | 選 SQL(PostgreSQL / MySQL) | 選 NoSQL(MongoDB) |
|---|---|---|
| 資料關聯 | 複雜多對多、需要複雜 JOIN | 簡單關聯、以 document 為主的讀取 |
| Schema 彈性 | 固定結構、各欄位型別明確 | 彈性、多型態、欄位隨時間演進 |
| 資料一致性 | 嚴格 ACID,強一致性,支援 Transaction | 可接受最終一致性(跨 document Transaction 有支援但較複雜) |
| 查詢複雜度 | 複雜聚合、多表 JOIN、報表查詢 | 以 document 為單位讀寫、簡單聚合 |
| 擴展方式 | 垂直擴展(加 CPU / RAM)為主 | 水平擴展(Sharding,加機器)原生支援 |
| 典型用例 | 金融系統、ERP、庫存管理、電商訂單 | 內容平台、IoT 資料、用戶行為日誌、商品目錄 |
考慮 SQL 的訊號
- • 資料之間有明確的關聯關係(訂單-商品-用戶)
- • 需要複雜的 JOIN 和聚合報表
- • 資料完整性要求極高(金融、醫療、庫存)
- • 團隊對 SQL 更熟悉
- • 需要嚴格的 Transaction 保證
考慮 MongoDB 的訊號
- • 資料結構不固定或頻繁演進(MVP 階段)
- • 以 document 為單位讀寫(博客、商品詳情)
- • 需要儲存 JSON/半結構化資料
- • 資料量超大,需要水平 Sharding
- • 快速開發、Schema 需要靈活調整
結論:工具,不是信仰
不是 NoSQL 比 SQL 好,而是不同工具解決不同問題。 很多大型系統兩個都用:PostgreSQL 管訂單和帳務, MongoDB 管用戶行為和內容,Redis 做快取, Elasticsearch 做全文搜尋。 選型的最佳答案永遠是:「哪個讓你的團隊能最快解決眼前的問題」。