Skip to content

ExpressJS - 数据库

动态 Web 应用程序需要数据库来持久化数据。本教程将指导你如何使用 Mongoose(一个用于 Node.js 的优雅对象数据模型 (ODM) 库)将现代 Express.js 应用程序连接到 MongoDB 数据库。

开始之前,请确保你的系统上已安装并运行 MongoDB,或者你可以访问基于云的 MongoDB 服务(例如 MongoDB Atlas)。

  1. **安装 Mongoose**:npm install mongoose
  2. **为环境变量安装 dotenv**:这是管理数据库连接字符串等敏感数据的关键最佳实践。npm install dotenv

在你的项目根目录中创建一个名为 .env 的文件。切勿将此文件提交到版本控制。

# .env 文件
# 你的 MongoDB 连接字符串
MONGO_URI=mongodb://127.0.0.1:27017/myModernAppDB
# 你的应用程序端口
PORT=3000

我们将创建一个专门的模块来处理数据库连接。这有助于提高代码的整洁性并实现关注点分离。

import mongoose from 'mongoose';
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1); // 以失败状态退出进程
}
};
export default connectDB;

现在,在你的主服务器文件(server.js 或 app.js)中,你可以建立连接了。

server.js
import express from 'express';
import dotenv from 'dotenv';
import connectDB from './config/db.js';
// 加载环境变量
dotenv.config();
// 连接到数据库
connectDB();
const app = express();
// ... 应用程序的其余配置

一个**模式(Schema)定义了集合中文档的结构,包括字段类型和验证。一个模型(Model)**是从模式定义编译而来的构造函数,它提供了与数据库交互的接口,用于创建、查询、更新和删除文档。

import mongoose from 'mongoose';
const personSchema = new mongoose.Schema({
name: {
type: String,
required: [true, '请提供姓名'],
trim: true
},
age: {
type: Number,
required: [true, '请提供年龄'],
min: [0, '年龄不能为负']
},
nationality: {
type: String,
required: false,
default: '未指定'
}
}, {
timestamps: true // 自动添加 createdAt 和 updatedAt 字段
});
const Person = mongoose.model('Person', personSchema);
export default Person;

现代 JavaScript 的 async/await 语法极大地简化了异步数据库操作,使得代码比旧的基于回调的方法更具可读性和可维护性。所有的数据库调用都应该用 try...catch 块包装起来,以实现健壮的错误处理。

// 在你的路由文件(例如 routes/people.js)中
import Person from '../models/Person.js';
// @desc 创建一个新人物
// @route POST /api/people
export const createPerson = async (req, res) => {
try {
// req.body 包含来自请求的已解析 JSON
const newPerson = await Person.create(req.body);
res.status(201).json({
success: true,
data: newPerson
});
} catch (error) {
res.status(400).json({ success: false, error: error.message });
}
};
// @desc 获取所有人物
// @route GET /api/people
export const getPeople = async (req, res) => {
try {
const people = await Person.find();
res.status(200).json({
success: true,
count: people.length,
data: people
});
} catch (error) {
res.status(500).json({ success: false, error: '服务器错误' });
}
};

注意:我们使用 PATCH 进行部分更新,这是一种现代的 RESTful 最佳实践。旧的 Model.update 和 Model.findByIdAndUpdate 已被取代。现代 Mongoose 建议获取文档、更新它,然后保存以触发中间件,或者使用带有特定选项的 findOneAndUpdate。

// @desc 更新一个人物
// @route PATCH /api/people/:id
export const updatePerson = async (req, res) => {
try {
const person = await mongoose.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true } // 选项
);
if (!person) {
return res.status(404).json({ success: false, error: '未找到人物' });
}
res.status(200).json({ success: true, data: person });
} catch (error) {
res.status(400).json({ success: false, error: error.message });
}
};

注意:remove() 方法已弃用。请使用 deleteOne()、deleteMany() 或 findByIdAndDelete()。

// @desc 删除一个人物
// @route DELETE /api/people/:id
export const deletePerson = async (req, res) => {
try {
const person = await mongoose.findByIdAndDelete(req.params.id);
if (!person) {
return res.status(404).json({ success: false, error: '未找到人物' });
}
res.status(200).json({ success: true, data: {} }); // 或者发送确认消息
} catch (error) {
res.status(500).json({ success: false, error: '服务器错误' });
}
};

使用 Postman、Insomnia 或 curl 等命令行工具来测试你的端点。例如,创建一个新人物:

curl -X POST http://localhost:3000/api/people \
-H 'Content-Type: application/json' \
-d '{"name":"Jane Doe","age":30,"nationality":"Canadian"}'