Mongoose 深度指南與 MongoDB 整合 Nodejs 後端開發資料操作與 Schema 設計

me
林彥成
2019-09-07 | 4 min.
文章目錄
  1. 1. 什麼是 Mongoose 及其在 Node.js 開發中的作用?
  2. 2. Mongoose 觀念與名詞
    1. 2.1. 什麼是 ODM/ORM?
  3. 3. 三步驟從資料庫到 API
    1. 3.1. Mongo DB 資料庫設定
    2. 3.2. Mongoose Schema 設計
    3. 3.3. Mongoose ODM 資料操作
  4. 4. Mongoose 專案架構
  5. 5. FAQ:Mongoose 與 MongoDB 資料操作常見問題
    1. 5.1. Q1:Mongoose 中的 Schema 與 Model 有什麼本質區別?
    2. 5.2. Q2:在設計 NoSQL 資料庫時,該如何選擇 Embedding 與 Referencing?
    3. 5.3. Q3:為什麼 Mongoose 連線時建議設定 useNewUrlParser 等選項?

什麼是 Mongoose 及其在 Node.js 開發中的作用?

Mongoose 是一款專為 Node.js 後端開發 設計的 MongoDB ODM (Object Data Modeling) 函式庫。其核心定義在於提供「基於 Schema」的解決方案,將 NoSQL 的彈性與強類型的結構化管理相結合。透過這份 Mongoose 深度解析,您可以掌握:1. Schema 設計:定義資料結構與驗證規則;2. Mongoose 資料操作:利用 Model 實例執行 CRUD 並自動映射為 JavaScript 物件;3. API 整合實作:將連線、模型與 Controller 解耦,構建可擴展的後端架構。相較於原生驅動,Mongoose 顯著提升了 軟體開發效率,並透過中間件與過濾器確保資料的一致性與安全性。


對於 Node.js 後端開發者而言,深入掌握 Mongoose 教學是提升開發效率與專案品質的關鍵。這款強大的工具作為 MongoDB ODM (Object Data Modeling) 解決方案,不僅簡化了資料庫的互動,更透過直觀的 Schema 設計,讓開發者能夠清晰地定義資料結構。

Mongoose,可以實現高效的 API 整合,使得資料的增刪改查變得更加便捷與安全,是構建現代化、可擴展後端服務的理想選擇。

Mongoose 觀念與名詞

Mongoose 提供了 schema-based 的解決方案,讓我們能直接操作 MongoDB 資料。在透過 Mongoose 操作資料庫時,有幾個關鍵名詞需要先有概念:

  1. Schema:定義資料庫模型結構的檔案,是 Mongoose 的核心。
  2. Model:由 Schema 當作參數產生的實例 (instance),可用來執行實際的資料庫操作。
  3. Collection:在 MongoDB 中的集合,等同於關聯式資料庫中的「表」。

什麼是 ODM/ORM?

由於像 Express 這類 Backend 框架無法直接操作資料庫,所以我們需要將資料表示為 JavaScript 的 Object,再透過 ODMORM 工具定義的資料 Schema 去操作資料庫。透過 Mongoose 就能有效達成操作 MongoDB 的目的。ODM/ORM 通常可以降低開發及維護成本,因此一般情況下都推薦使用。

  • ODM (Object Data Model):主要對應 NoSQL 資料庫,如 MongoDB
  • ORM (Object Relational Model):主要對應 SQL-Based 資料庫。

三步驟從資料庫到 API

透過 Mongoose 串接 MongoDB 並提供 API 服務,大致可分為以下三個步驟:

  1. MongoDB 資料庫設定
  2. Mongoose Schema 設計
  3. Mongoose ODM 資料操作

Mongo DB 資料庫設定

最常用的就是運用 Mongoose 搭配 MongoDB

  1. 在安裝完 Mongo 後,進入 shell 去連線看看 mongo --port 27017
  2. 成功連線後可以選擇資料庫開始下指令,像是 use test
  3. 進入 test 中設定使用者及權限:
1
2
3
4
5
6
db.dropAllUsers();
db.createUser({
user: "test",
pwd: "test",
roles: [{ role: "readWrite", db: "test" }],
});
  1. 資料庫為了安全起見會要將資料庫的 authorization 打開,windows 請參考連結,ubuntu 請去編輯 etc 資料夾底下的 Mongo 設定,加入設定如下:
1
2
security:
authorization: enabled

Mongoose Schema 設計

要使用 Mongoose 操作 MongoDB 的第一步就是要從定義 Schema 開始。定義完成後,Schema 會自動對應到 MongoDB 中的一個 collection。另外,因為不像傳統資料庫那樣有 join 的概念,所以拿資料的時候可以依照我們的使用情境去設計,像是以撈取為主的話就可以透過雙向參照的設計去加速。詳細可以參考MongoDB Schema 設計指南,分類有以下幾種:

  • Modeling One-to-Few 少量級關聯模式 (Embedding)
  • One-to-Many 多量級關聯模式 (Child-Referencing)
  • One-to-Squillions 海量級關聯模式 (Parent-Referencing)
  • Two-Way Referencing (雙向參照設計)
  • 多對一反正規化 (Denormalizing from Many -> One)

Mongoose ODM 資料操作

Mongoose 則協助我們在 Node.js Backend 專案中操作 MongoDB。在程式中定義好 Schema(不需要手動開啟欄位),確認資料庫連線沒有問題就可以直接開始操作了。

比較大的問題是 Node.js 不像 C#.net 那樣的語言有工具可以自動產生程式碼和架構,所以這個部分就是看每個人的狀況去放置,但還是以關注點分離的概念為主:

  1. 建立跟 MongoDB 的連線
1
2
3
4
5
6
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/test", {
useNewUrlParser: true,
useUnifiedTopology: true,
// ... 其他選項
});
  1. 在 model 中定義 Schema 並創造一個 Model
1
2
3
4
5
6
7
8
9
10
/**
* user model
*/

const userSchema = mongoose.Schema({
id: String,
// ... 其他欄位
});

module.exports = mongoose.model("user", userSchema);
  1. 使用剛剛產生的 Model 實例在 controller 中撈資料
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* user controller
*/

const getUser = (id) => {
return new Promise((resolve, reject) => {
const User = require("./model");
User.findOne({ id }).exec((error, docs) => {
if (error) return reject(error);
resolve(docs);
});
});
};
  1. 透過 route 開 API 給前端使用
1
2
3
4
5
6
7
8
9
10
const express = require("express");
const app = express();
app.get("/api/v1/user", async (req, res) => { // 使用 async/await 處理 Promise
try {
const user = await getUser("defaultID");
res.json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
});

Mongoose 專案架構

通常 Mongoose 會搭配一個 Backend 框架來做使用,像是 Express 或是 Koa 等等。在網路上常見的專案架構有兩種:

  1. 第一種是依照資料表去做區分,把同個資料表的 Model、controller、route 集中存放,這種方式覺得較適合大型專案。
1
2
3
4
5
6
7
8
9
10
11
├── src/
│ ├── entities/ # 按照資料表去區分
│ │ └── user/ # 使用者表
│ │ ├── model.js # Schema 定義
│ │ ├── controller.js # 資料庫 CRUD
│ │ └── route.js # API 設定
│ └── index.js # 入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md
  1. 第二種則是依照功能性,controller、routes、models 集中放置在各自的分類資料夾,這種方式覺得較適合小型專案。
1
2
3
4
5
6
7
8
9
├── src/
│ ├── controller/ # 資料庫 CRUD
│ ├── routes/ # API 設定
│ ├── models/ # Schema 定義
│ └── index.js # 程式入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md

FAQ:Mongoose 與 MongoDB 資料操作常見問題

Q1:Mongoose 中的 Schema 與 Model 有什麼本質區別?

A:Schema 是藍圖,它定義了資料的形狀(欄位、類型、預設值、驗證);而 Model 則是根據 Schema 產生的構造函數,它是與資料庫互動的入口。您可以把 Schema 想像成「類別 (Class)」的定義,而 Model 則是可以用來執行 find, create 等方法的單例實體。在 Node.js 後端開發 中,我們通常一個檔案定義一個 Schema 並匯出一個 Model。

Q2:在設計 NoSQL 資料庫時,該如何選擇 Embedding 與 Referencing?

A:這取決於您的讀寫頻率與資料量。Embedding (內嵌) 適合「一對少」且資料常同時讀取的場景(如:文章與其標籤),優點是查詢極快。Referencing (引用) 適合「一對多」或海量數據場景(如:使用者與其數萬筆日誌),優點是避免單一 Document 超過 MongoDB 的 16MB 限制。高品質的 NoSQL 資料庫設計 往往會混用這兩者,甚至使用「雙向參照」來達到效能平衡。

Q3:為什麼 Mongoose 連線時建議設定 useNewUrlParser 等選項?

A:MongoDB 的 Node.js 驅動程序不斷演進,舊有的 URL 解析器與監測機制已被標記為過時。設定這些選項是為了確保 Mongoose 使用最新的底層協定來與資料庫溝通,避免出現連線不穩或安全性警告。此外,在高併發環境下,建議配置 poolSize(連線池大小)以優化 軟體開發效率 與系統吞吐量。



喜歡這篇文章,請幫忙拍拍手喔 🤣