Mongoose Schema:資料建模與 CRUD 完整操作指南

在 Mongoose 的世界中,所有操作都圍繞著兩個核心:Schema (定義資料結構的藍圖) 與 Model (根據藍圖產出的操作工具)。掌握它們,你就能在 Node.js 中優雅地操縱 MongoDB。

定義 Schema 與資料校驗

Schema 不僅定義欄位,還負責資料的完整性。

const mongoose = require('mongoose');

const postSchema = new mongoose.Schema(
  {
    title: {
      type: String,
      required: [true, '標題為必填'],
      trim: true, // 自動修剪空格
      maxLength: [100, '標題太長了'],
    },
    content: {
      type: String,
      required: [true, '內容不可為空'],
    },
    status: {
      type: String,
      enum: ['draft', 'published'], // 限定值範圍
      default: 'draft',
    },
    author: {
      type: mongoose.Schema.ObjectId, // 建立與 User 集合的關聯
      ref: 'User',
    },
  },
  { timestamps: true }
); // 自動生成 createdAt 與 updatedAt

const Post = mongoose.model('Post', postSchema);
module.exports = Post;

實戰 CRUD:基礎與進階操作

1. Create (建立)

const post = await Post.create({
  title: 'Node.js 與 Mongoose 實戰',
  content: '這是一篇深度解析的文章...',
});

2. Read (讀取與關聯)

當你有關聯資料時,使用 populate 可以像 SQL 的 JOIN 一樣拉出詳細資訊。

// 尋找文章並同時抓取作者的 name 資訊
const posts = await Post.find().populate('author', 'name');

// 效能優化:如果是唯讀操作,使用 lean() 能轉為原生物件,大幅提升速度
const fastResult = await Post.find().lean();

3. Update (更新)

// 注意:findByIdAndUpdate 預設不會觸發 Schema 的驗證,需加上 runValidators
const updated = await Post.findByIdAndUpdate(
  id,
  { status: 'published' },
  { new: true, runValidators: true }
);

4. Delete (刪除)

await Post.findByIdAndDelete(id);

進階:Middleware (Hooks) 的應用

最常見的用法是在存檔前對密碼進行處理,或是在內容變動時記錄日誌。

// 在存檔 (save) 之前自動執行的邏輯
postSchema.pre('save', function (next) {
  this.title = this.title.toUpperCase(); // 強制轉換為大寫
  next();
});

實務建議:Instance vs Static Methods

  • Instance Method:針對「特定一筆資料」的方法(如 user.checkPassword())。
  • Static Method:針對「整張表」的查詢邏輯(如 Post.findByCategory())。

總結

  1. Schema 是資料的防線,善用內建的校驗器(required, enum, match)。
  2. 在大量讀取且不需要修改資料時,務必開啟 .lean() 模式優化效能。
  3. 建立 Model 關聯 並使用 populate() 能讓你輕鬆處理複雜的資料鏈結。