博客 / 詳情

返回

MongoDB 的文檔模型與 CRUD 實戰

對於開發者而言,數據庫的選擇往往決定了應用程序的架構靈活性。不少開發者應該都熟悉傳統的關係型數據庫(如 MySQL 或 PostgreSQL),初次接觸 MongoDB 時可能會感到一種思維模式的轉變。

今天一起來探討 MongoDB 為何被設計成現在的樣子,以及如何進行基礎的增刪改查(CRUD)操作。

image.png

關係型數據庫的世界

在關係型數據庫中,數據被整齊地排列在行和列中,就跟 Excel 表格似的。表結構(Schema)在數據寫入前就必須定義好。每一行都要遵循這個規則。

這種設計能確保數據的一致性和邏輯嚴密性。但在面對快速迭代的現代應用時,這種剛性可能成為瓶頸。如果業務需求變更,需要給現有的億級大表增加一個字段,那遷移工作就複雜多了,還有潛在的停機風險。

NoSQL = Not Only SQL

NoSQL 並不是不要SQL,我覺得它更傾向於 Not Only SQL

並不是説要拋棄關係型數據庫,而是在工具箱中增加一個新的選項。對於社交網絡、遊戲日誌、物聯網數據等非結構化或半結構化數據,我們需要一種更靈活的存儲方式。MongoDB 正是其中的佼佼者,屬於文檔型數據庫(Document-Oriented)

核心概念:文檔與集合

MongoDB 不再將數據拆散存儲在不同的行和列中,而是將一個完整的對象存儲為一個文檔(Document)

文檔 (Document)

文檔是 MongoDB 的最小數據單元。它看起來非常像 JSON 對象,但技術上,MongoDB 使用的是 BSON(Binary JSON)。BSON 是一種二進制格式,讀寫速度更快,且支持 JSON 無法表達的數據類型(如日期、二進制數據等)。

文檔強就強在它能嵌套。開發者可以將列表、對象直接存入一個字段中,而不需要像 SQL 那樣建立多張關聯表。

代碼示例:一個電商訂單文檔

以下代碼展示了一個包含嵌套對象(收貨地址)和數組(商品列表)的文檔結構,這在 MongoDB 中是標準寫法:

{
  // 唯一標識符,相當於主鍵
  "_id": ObjectId("64b8f1e2a9b3c5d6e7f8a9b0"),
  // 支持存儲具體的日期類型
  "created_at": ISODate("2024-05-20T09:30:00Z"),
  "status": "Processing",
  
  // 嵌套對象:無需拆分到另一張表
  "delivery_info": {
    "Country": "France",
    "city": "Paris",
    "detail": "Avenue des Champs Elysées"
  },
  
  // 數組結構:直接存儲列表數據
  "cart_items": [
    {
      "sku": "KB-MECHANICAL-01",
      "count": 1,
      "unit_price": 599.00
    },
    {
      "sku": "MOUSE-PAD-XL",
      "count": 2,
      "unit_price": 49.50
    }
  ]
}

集合 (Collection)

如果説文檔對應 SQL 中的“行”,那麼集合(Collection)就對應 SQL 中的“表”。

最大的區別是它的動態模式(Dynamic Schema) 。在同一個集合中,文檔的結構可以不完全相同。例如,在 users 集合中,有的用户可能有 wechat_id 字段,而有的用户只有 email 字段。這種靈活性讓數據建模更貼近面向對象編程的邏輯。

核心字段:_id

每個文檔都必須有一個 _id 字段,作為主鍵。如果在插入數據時沒有指定,MongoDB 會自動生成一個全局唯一的 ObjectId。這個 ID 包含了時間戳信息,因此甚至可以從 ID 中推算出數據的創建時間。

    • *

基礎實戰:CRUD 操作

假設我們已經連接到了數據庫(使用 mongosh 或圖形化工具),下面演示如何對一個名為 employees的集合進行操作。

新增 (Create)

使用 insertOne 插入單條數據,或 insertMany 插入多條數據。

  • 插入單條數據
// 向 employees 集合中添加一名新員工
db.employees.insertOne({
  name: "Jack",
  department: "Engineering",
  is_manager: false,
  skills: ["Java", "Docker"],
  onboard_date: new Date()
})
  • 插入多條數據
// 一次性添加多名實習生
db.employees.insertMany([
   {
     name: "Mike",
     role: "Intern",
     age: 21,
     mentor: "Jack"
   },
   {
     name: "Tommy",
     role: "Intern",
     age: 22,
     mentor: "Jack"
   }
])

查詢 (Read)

  • 查詢單條 ( findOne ) :返回匹配條件的第一條數據。常用於根據 ID 或唯一字段查找。
// 查找名字是 'Jack' 的員工
db.employees.findOne({ name: 'Jack' })
  • 查詢多條 ( find ) :返回所有匹配的數據。支持複雜的篩選操作符。
// 查詢所有年齡大於 21 歲的員工
// $gt 表示 greater than (大於)
db.employees.find({ age: { $gt: 21 } })

更新 (Update)

更新操作通常包含兩部分:篩選條件更新動作(例如 $set)。

  • 更新單條 ( updateOne )
// 找到名字是 'Tommy' 的員工,將其職位修改為 'Junior Developer'
db.employees.updateOne(
  { name: 'Tommy' },       // 篩選條件
  { $set: { role: 'Junior Developer' } } // 更新動作
)
  • 更新多條 ( updateMany )
// 為所有沒有 'location' 字段的員工,添加默認辦公地點
// $exists: false 用於判斷字段不存在
db.employees.updateMany(
  { location: { $exists: false } }, 
  { 
    $set: { 
      "location": "New York",
      "wfh_allowed": true
    } 
  }
);

刪除 (Delete)

  • 刪除單條 ( deleteOne )
// 刪除第一個匹配到的名字為 'Mike' 的記錄
db.employees.deleteOne({ name: "Mike" })
  • 刪除多條 ( deleteMany )
// 刪除所有實習生記錄
db.employees.deleteMany({ role: "Intern" });
注意:如果執行 db.employees.deleteMany({})(空篩選條件),將會清空整個集合,操作時需格外謹慎。
    • *

搭建高效的本地開發環境

理解了理論和基礎指令後,下一步就是在本地環境中進行實戰演練。

對於開發者來説,維護本地數據庫環境比較繁瑣。可能需要安裝 Docker,編寫複雜的 Compose 文件,或者在系統中通過命令行安裝不同版本的數據庫,還要處理端口衝突和版本依賴問題。

但這些問題在ServBay面前都是小Case,因為ServBay 能夠極大簡化這一流程。它不僅支持一鍵安裝 MongoDB,更解決了多版本共存的痛點。

image.png

ServBay 的核心優勢:

  • 多版本同時運行:ServBay支持運行 MongoDB 5.0 到 8.0 的實例,互不干擾。這對於維護不同歷史時期的項目非常方便,無需反覆卸載重裝。
  • 全棧數據庫支持:除了 MongoDB,ServBay 還囊括了 MySQL、PostgreSQL、MariaDB 以及 Redis、Memcached 等主流 NoSQL 數據庫。
  • 實例隔離:支持同時運行多個不同類型的數據庫實例,為每個項目提供獨立的沙盒環境。
  • 極簡配置:告別繁雜的配置文件,通過直觀的圖形界面即可管理服務狀態和端口。

如果你希望跳過繁瑣的環境配置,直接進入代碼開發和數據庫結構設計的核心環節,ServBay 會是一個得力的助手。它讓數據庫的安裝和管理變得像手機安裝 App 一樣簡單,讓你能專注於構建更優秀的應用程序。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.