昨天我用 MongoDB + Mongoose,體驗了 NoSQL 文件型資料庫的彈性。
今天換一個角度:來接觸 關聯式資料庫(SQL),選擇的是 PostgreSQL。
這樣一來,我就能比較 NoSQL 跟 SQL 的差異,也能讓 Todo API 支援不同的資料庫後端。
PostgreSQL 是一個功能強大的開源關聯式資料庫,資料以「表格(Table)」形式存放,跟 Excel 很像。
要使用它,就得先定義欄位(schema),每筆資料必須符合這個結構。
舉例:一個 todos
表格可能會長這樣:
id | task | done |
---|---|---|
1 | 學 Node.js | false |
2 | 寫鐵人賽文章 | true |
專案裡安裝 pg
(PostgreSQL 的官方 Node.js 驅動):
npm install pg
在 PostgreSQL 裡先建立一個資料庫 todo_app
,再建立 todos
table:
CREATE DATABASE todo_app;
\c todo_app;
CREATE TABLE todos (
id SERIAL PRIMARY KEY,
task TEXT NOT NULL,
done BOOLEAN DEFAULT false
);
import pkg from "pg";
const { Pool } = pkg;
export const pool = new Pool({
user: "postgres", // 預設帳號
host: "localhost",
database: "todo_app",
password: "你的密碼",
port: 5432,
});
延續前幾天的 app.js
,把原本的記憶體陣列改成用 PostgreSQL 存取。
import express from "express";
import { pool } from "./db.js";
const app = express();
const port = 3000;
app.use(express.json());
// GET /todos → 查詢所有資料
app.get("/todos", async (req, res) => {
const result = await pool.query("SELECT * FROM todos ORDER BY id ASC");
res.json(result.rows);
});
// POST /todos → 新增一筆資料
app.post("/todos", async (req, res) => {
const { task } = req.body;
if (!task) {
return res.status(400).json({ error: "task 欄位必填" });
}
const result = await pool.query(
"INSERT INTO todos (task) VALUES ($1) RETURNING *",
[task]
);
res.status(201).json(result.rows[0]);
});
app.listen(port, () => {
console.log(`伺服器已啟動:http://localhost:${port}`);
});
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"task": "Day 16 - PostgreSQL 練習"}'
輸出:
{ "id": 1, "task": "Day 16 - PostgreSQL 練習", "done": false }
curl http://localhost:3000/todos
輸出:
[
{ "id": 1, "task": "Day 16 - PostgreSQL 練習", "done": false }
]
今天接觸了 PostgreSQL,跟昨天的 MongoDB 感覺很不一樣:
pg
就是直接寫 SQL,比較接近資料庫本身的語法。能體驗這兩種資料庫的差異,讓我更清楚什麼情境適合用 SQL,什麼情境適合用 NoSQL。