
前言
在上一篇文章中,我們初步建立了 MongoDB Atlas 的帳號,並且快速認識了 Mongoose,接下來當然就是要來整合再一起啦~
Express 與 Mongoose
首先一開始的一些起手式我就不再次說明了,直接附上指令讓你可以快速建立一個專案:
1
| mkdir example-express-mongoose
|
1
| cd example-express-mongoose
|
理論上來說,上面的指令你應該沒有任何一行看不懂的,如果有,那就代表你沒有認真看前面的文章,建議你可以先回去看看~

那麼我們這次要寫什麼呢?其實很簡單,把前面寫的範例程式碼把它整合到一起就好了,所以我們先來看看前面的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const express = require('express'); const app = express();
const data = [];
app.use(express.json());
app.get('/todos', (req, res) => { res.send(data); });
app.post('/todos', (req, res) => { const { title, completed } = req.body;
data.push({ id: new Date().getTime(), title: cacheBody.title, completed: cacheBody.completed, });
res.send(data); });
app.listen(3000)
|
接下來,補上我們前一篇所使用的 Mongoose 的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const express = require('express'); const mongoose = require('mongoose');
const app = express();
mongoose.connect('mongodb+srv://example:[email protected]/?retryWrites=true&w=majority') .then(() => console.log('Connected to MongoDB...'))
app.listen(3000)
|
當你在終端機輸入 npm start or node index.js 後,你會看到 Mongoose 已經幫你連上 MongoDB Atlas 了囉~
解決 Mongoose 連接問題
這時候有些人應該會有個好奇的疑問點…
「如果我在 Mongoose 連接成功之前,就已經有人來存取我的 API 了,那不是會出錯嗎?」
這個問題問得很好,確實是有這種可能性會發生,如果我們的專案在成功連接之前,就先接受了 API 請求,而剛好這些 API 請求需要操控資料庫的話,那麼確實是會出錯沒有錯。
那麼我們該怎麼解決這個麻煩的問題呢?其實我們只需要善加利用前面所學的 Middleware 就可以了,我們可以在 Middleware 中判斷是否已經連接成功,如果沒有的話,就回傳一個錯誤訊息,如果有的話,就繼續執行下一個 Middleware。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const express = require('express'); const mongoose = require('mongoose'); const app = express();
async function connectMongoDB () { try { await mongoose.connect('mongodb+srv://example:[email protected]/?retryWrites=true&w=majority') console.log('Connected to MongoDB...') connectStatus = true; } catch (error) { console.log(error) } }
connectMongoDB()
app.use(express.json());
app.use((req, res, next) => { if (connectStatus) { next(); } else { res.status(503).send({ status: false, message: 'Server is not ready' }); } })
app.listen(3000)
|
這樣子我們就可以避免在 Mongoose 還沒跟 MongoDB Atlas 連接成功之前,就先接受 API 請求的問題囉!
定義 Schema
在準備跟 MongoDB 互動(ex:CRUD)之前,我們必須先定義 Schema,這樣子才能夠讓 Mongoose 知道我們要存取的資料長什麼樣子。
1 2 3 4 5
| const todoSchema = new mongoose.Schema({ id: Number, title: String, completed: Boolean, });
|
Note
CRUD 意指 Create、Read、Update、Delete,也就是我們常說的「增刪改查」。
那麼什麼是 Schema 呢?Schema 是用來定義 MongoDB 結構的一種概念,主要說明了這些資料的型別、欄位名稱、預設值等等,這樣子我們才能夠在存取資料時,知道該怎麼去存取。
因此以剛剛的範例程式碼來講,我們定義了一個 todoSchema,裡面有兩個欄位,分別是 title 跟 completed,而這兩個欄位的型別分別是 String 跟 Boolean。
那麼只要是這些 Schema 屬性之外的資料,都會被忽略,也就是說,如果我們在存取資料時,傳入了一個多餘的欄位,那麼這個欄位就會被忽略,不會被存到資料庫中。
透過 Schema 可以確保我們資料的一致性和完整性。
定義 Model
定義完 Schema 之後,接著就是要來建立 Model,通常 Modal 會對應特定的 Schema,而且每個 Model 都會跟資料庫中的一個 collection 對應,也就是說,我們可以透過 Model 來存取資料庫中的資料。
1 2 3 4 5 6 7
| const todoSchema = new mongoose.Schema({ id: Number, title: String, completed: Boolean, });
const Todo = mongoose.model('Todo', todoSchema);
|
你也可以把 mongoose.model 當作 new 實例化的概念沒有錯,因為它們的用法很像,只是 mongoose.model 是用來建立 Model 的,而 new 則是用來建立實例的。
透過這個 Modal 我們就可以針對資料庫做 CRUD(增刪改查)的動作囉!
存取資料庫與寫入資料
那麼目前我們完整程式碼長怎樣呢?我們先來看一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| const express = require('express'); const mongoose = require('mongoose'); const app = express();
let connectStatus = false;
async function connectMongoDB () { try { await mongoose.connect('mongodb+srv://example:[email protected]/?retryWrites=true&w=majority') console.log('Connected to MongoDB...') connectStatus = true; } catch (error) { console.log(error) } }
connectMongoDB()
const data = [];
app.use(express.json());
app.use((req, res, next) => { if (connectStatus) { next(); } else { res.status(503).send({ status: false, message: 'Server is not ready' }); } })
const todoSchema = new mongoose.Schema({ id: Number, title: String, completed: Boolean, });
const Todo = mongoose.model('Todo', todoSchema);
app.get('/todos', (req, res) => { res.send(data); });
app.post('/todos', (req, res) => { const { title, completed } = req.body;
data.push({ id: new Date().getTime(), title: cacheBody.title, completed: cacheBody.completed, });
res.send(data); });
app.listen(3000)
|
我們第一個要做的事情是先來做 Post 的動作,也就是寫入資料庫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const express = require('express');
app.post('/todos', async (req, res) => { const { title, completed } = req.body;
const todo = new Todo({ id: new Date().getTime(), title, completed, });
await todo.save(); res.send({ status: true, message: 'Create todo successfully', }); });
app.listen(3000)
|
其實我們可以發現實作難度真的不高,只要透過 new 來建立一個實例,然後透過 save 來存入資料庫就可以了。
取得 Todo 資料的話更簡單了,只需要透過 find 就可以取得資料庫中的資料囉!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const express = require('express');
app.get('/todos', async (req, res) => { const todos = await Todo.find(); res.send({ status: true, data: todos, }); });
app.listen(3000)
|
基本上以上程式碼你就可以透過 Postman 來測試了,不意外的話,當你打完 Post /todos 之後,你會發現資料庫中多了一筆資料,接著你在打 Get /todos 之後,你會得到以下資料
1 2 3 4 5 6 7 8 9 10 11 12
| { "status": true, "data": [ { "_id": "64e08a11f5e1d20be8115fb0", "id": 1692437009750, "title": "Hello", "completed": false, "__v": 0 } ] }
|
恭喜你,基本的新增與讀取的功能完成囉!
剩下的編輯與刪除的部分,我也想保留給你作為小功課,你可以試著自己實作看看,這邊我也補充相關資源讓你可以參考
以上資源我相信可以幫助你做出來的。
那麼這邊你應該會好奇 __v 與 _id 這兩個屬性是什麼東西,這邊我也做一下補充。
這兩個屬性是 MongoDB 預設的屬性,_id 是 MongoDB 的主鍵(key),而 __v 則是版本鍵(version key),比較需要注意的是 _id 是 ObjectId,而不是我們一般的數字。
如果你希望不要有這兩個屬性,你可以透過 select 來過濾掉
1
| const todos = await Todo.find().select('-__v -_id');
|
那麼這一篇差不多就先到這些結束,我們下一篇見。
碎碎念
終於來到第十一天了,其實我發現我身上的存稿真的不是很夠 Orz
而且我現在人正在日本發文唷~
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
Advertisement