MongoDB集成 #
一、MongoDB简介 #
1.1 什么是MongoDB? #
MongoDB是一个基于文档的NoSQL数据库,使用JSON格式存储数据,具有高性能、高可用性和易扩展性。
1.2 特点 #
- 文档存储,灵活的数据结构
- 支持索引,查询性能高
- 支持复制和分片
- 丰富的查询语言
1.3 安装 #
bash
npm install mongoose
二、连接MongoDB #
2.1 基本连接 #
javascript
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/myapp')
.then(() => console.log('连接成功'))
.catch(err => console.error('连接失败:', err));
2.2 连接选项 #
javascript
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
maxPoolSize: 10
});
2.3 连接事件 #
javascript
mongoose.connection.on('connected', () => {
console.log('数据库连接成功');
});
mongoose.connection.on('error', (err) => {
console.error('数据库连接错误:', err);
});
mongoose.connection.on('disconnected', () => {
console.log('数据库连接断开');
});
process.on('SIGINT', async () => {
await mongoose.connection.close();
process.exit(0);
});
2.4 配置文件 #
config/database.js:
javascript
const mongoose = require('mongoose');
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.DATABASE_URL);
console.log(`数据库连接成功: ${conn.connection.host}`);
} catch (error) {
console.error('数据库连接失败:', error.message);
process.exit(1);
}
};
module.exports = connectDB;
三、Schema定义 #
3.1 基本Schema #
javascript
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, '请输入用户名'],
trim: true,
maxlength: [50, '用户名不能超过50个字符']
},
email: {
type: String,
required: [true, '请输入邮箱'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, '请输入有效的邮箱地址']
},
password: {
type: String,
required: [true, '请输入密码'],
minlength: [6, '密码至少6个字符'],
select: false
},
age: {
type: Number,
min: [0, '年龄不能小于0'],
max: [150, '年龄不能大于150']
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user'
},
isActive: {
type: Boolean,
default: true
},
createdAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('User', userSchema);
3.2 数据类型 #
| 类型 | 说明 |
|---|---|
| String | 字符串 |
| Number | 数字 |
| Date | 日期 |
| Boolean | 布尔值 |
| Object | 对象 |
| Array | 数组 |
| ObjectId | 文档ID |
| Buffer | 二进制数据 |
| Decimal128 | 高精度数字 |
3.3 嵌套文档 #
javascript
const orderSchema = new mongoose.Schema({
orderNumber: String,
customer: {
name: String,
email: String,
address: {
street: String,
city: String,
zipCode: String
}
},
items: [{
product: String,
quantity: Number,
price: Number
}]
});
3.4 引用关系 #
javascript
const postSchema = new mongoose.Schema({
title: String,
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}]
});
const commentSchema = new mongoose.Schema({
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}
});
四、模型方法 #
4.1 实例方法 #
javascript
userSchema.methods.comparePassword = async function(password) {
return await bcrypt.compare(password, this.password);
};
userSchema.methods.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};
const user = await User.findById(id);
const isMatch = await user.comparePassword('password123');
4.2 静态方法 #
javascript
userSchema.statics.findByEmail = function(email) {
return this.findOne({ email });
};
userSchema.statics.findActive = function() {
return this.find({ isActive: true });
};
const user = await User.findByEmail('test@example.com');
const activeUsers = await User.findActive();
4.3 虚拟属性 #
javascript
userSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
userSchema.virtual('passwordConfirmation')
.set(function(value) {
this._passwordConfirmation = value;
});
userSchema.set('toJSON', { virtuals: true });
userSchema.set('toObject', { virtuals: true });
4.4 中间件 #
javascript
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) {
return next();
}
this.password = await bcrypt.hash(this.password, 10);
next();
});
userSchema.post('save', function(doc) {
console.log('用户保存成功:', doc._id);
});
userSchema.pre('remove', function(next) {
Post.deleteMany({ author: this._id }).exec();
next();
});
五、CRUD操作 #
5.1 创建文档 #
javascript
const user = await User.create({
name: '张三',
email: 'zhangsan@example.com',
password: 'password123'
});
const user = new User({ name, email, password });
await user.save();
5.2 查询文档 #
javascript
const users = await User.find();
const users = await User.find({ role: 'admin' });
const user = await User.findById(id);
const user = await User.findOne({ email: 'test@example.com' });
const user = await User.findById(id).select('-password');
const users = await User.find().sort({ createdAt: -1 }).limit(10);
5.3 更新文档 #
javascript
await User.findByIdAndUpdate(id, { name: '新名字' });
await User.findByIdAndUpdate(id, { $set: { name: '新名字' } });
await User.updateMany({ role: 'user' }, { isActive: true });
const user = await User.findById(id);
user.name = '新名字';
await user.save();
5.4 删除文档 #
javascript
await User.findByIdAndDelete(id);
await User.deleteOne({ email: 'test@example.com' });
await User.deleteMany({ isActive: false });
六、查询进阶 #
6.1 条件操作符 #
javascript
await User.find({ age: { $gt: 18 } });
await User.find({ age: { $gte: 18, $lte: 60 } });
await User.find({ name: { $in: ['张三', '李四'] } });
await User.find({ name: { $nin: ['张三', '李四'] } });
await User.find({ email: { $exists: true } });
6.2 逻辑操作符 #
javascript
await User.find({ $or: [{ role: 'admin' }, { age: { $gt: 30 } }] });
await User.find({ $and: [{ role: 'user' }, { isActive: true }] });
await User.find({ age: { $not: { $gt: 18 } } });
await User.find({ $nor: [{ role: 'admin' }, { age: { $lt: 18 } }] });
6.3 正则表达式 #
javascript
await User.find({ name: /^张/ });
await User.find({ email: /gmail\.com$/ });
await User.find({ name: { $regex: '张', $options: 'i' } });
6.4 填充引用 #
javascript
const posts = await Post.find().populate('author');
const posts = await Post.find().populate('author', 'name email');
const posts = await Post.find().populate({
path: 'comments',
populate: { path: 'author' }
});
6.5 分页查询 #
javascript
const page = 1;
const limit = 10;
const skip = (page - 1) * limit;
const users = await User.find()
.skip(skip)
.limit(limit)
.sort({ createdAt: -1 });
const total = await User.countDocuments();
const totalPages = Math.ceil(total / limit);
七、索引 #
7.1 创建索引 #
javascript
userSchema.index({ email: 1 });
userSchema.index({ email: 1 }, { unique: true });
userSchema.index({ name: 1, age: -1 });
userSchema.index({ content: 'text' });
7.2 索引类型 #
| 类型 | 说明 |
|---|---|
| 单字段索引 | 单个字段 |
| 复合索引 | 多个字段 |
| 唯一索引 | 值唯一 |
| 文本索引 | 全文搜索 |
| 地理空间索引 | 位置查询 |
八、完整示例 #
8.1 模型文件 #
models/User.js:
javascript
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, '请输入用户名'],
trim: true,
maxlength: [50, '用户名不能超过50个字符']
},
email: {
type: String,
required: [true, '请输入邮箱'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, '请输入有效的邮箱地址']
},
password: {
type: String,
required: [true, '请输入密码'],
minlength: [6, '密码至少6个字符'],
select: false
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user'
},
avatar: String,
isActive: {
type: Boolean,
default: true
}
}, {
timestamps: true
});
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 10);
});
userSchema.methods.comparePassword = async function(password) {
return await bcrypt.compare(password, this.password);
};
userSchema.methods.toJSON = function() {
const user = this.toObject();
delete user.password;
return user;
};
module.exports = mongoose.model('User', userSchema);
8.2 服务文件 #
services/userService.js:
javascript
const User = require('../models/User');
const userService = {
async findAll(options = {}) {
const { page = 1, limit = 10, sort = '-createdAt' } = options;
const skip = (page - 1) * limit;
const [users, total] = await Promise.all([
User.find().skip(skip).limit(limit).sort(sort),
User.countDocuments()
]);
return {
users,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
};
},
async findById(id) {
return await User.findById(id);
},
async findByEmail(email) {
return await User.findOne({ email });
},
async create(userData) {
const user = new User(userData);
return await user.save();
},
async update(id, userData) {
return await User.findByIdAndUpdate(
id,
{ $set: userData },
{ new: true, runValidators: true }
);
},
async delete(id) {
return await User.findByIdAndDelete(id);
}
};
module.exports = userService;
九、总结 #
MongoDB集成要点:
| 概念 | 说明 |
|---|---|
| 连接 | mongoose.connect() |
| Schema | 定义数据结构 |
| Model | 操作数据库 |
| CRUD | 增删改查 |
| 查询 | 条件、排序、分页 |
| 索引 | 提升查询性能 |
下一步,让我们学习MySQL集成!
最后更新:2026-03-28