Mongoose是Node.js 操作 MongoDB 的优雅解决方案
Mongoose 是一个基于 Node.js 的 MongoDB 对象建模工具,它为 Node.js 与 MongoDB 之间提供了一个高级抽象层,使开发者可以更便捷地操作 MongoDB。
1. 安装与基本设置
首先安装 Mongoose:
npm install mongoose
连接到 MongoDB 数据库:
const mongoose = require('mongoose');
async function connectDB() {
try {
await mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false
});
console.log('Connected to MongoDB');
} catch (error) {
console.error('Error connecting to MongoDB:', error);
process.exit(1);
}
}
connectDB();
2. 核心概念:Schema、Model 和 Document
Schema(模式)
定义数据结构和验证规则:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const userSchema = new Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
validate: {
validator: (value) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
},
message: 'Invalid email address'
}
},
age: {
type: Number,
min: 1,
max: 150
},
createdAt: {
type: Date,
default: Date.now
}
});
Model(模型)
基于 Schema 创建数据模型:
const User = mongoose.model('User', userSchema);
Document(文档)
模型的实例,代表 MongoDB 中的一个文档:
const newUser = new User({
name: 'John Doe',
email: '[email protected]',
age: 30
});
newUser.save()
.then(user => console.log('User saved:', user))
.catch(error => console.error('Error saving user:', error));
3. 数据验证
Mongoose 提供内置和自定义验证器:
const productSchema = new Schema({
name: {
type: String,
required: [true, 'Product name is required'],
minlength: [3, 'Name must be at least 3 characters']
},
price: {
type: Number,
required: true,
validate: {
validator: (value) => value > 0,
message: 'Price must be greater than 0'
}
},
category: {
type: String,
enum: {
values: ['electronics', 'clothing', 'books'],
message: '{VALUE} is not a valid category'
}
}
});
4. 数据操作
创建文档
// 单个创建
User.create({ name: 'Alice', email: '[email protected]', age: 25 })
.then(user => console.log('Created user:', user))
.catch(error => console.error('Error creating user:', error));
// 批量创建
User.insertMany([
{ name: 'Bob', email: '[email protected]', age: 30 },
{ name: 'Charlie', email: '[email protected]', age: 35 }
])
.then(users => console.log('Created users:', users))
.catch(error => console.error('Error creating users:', error));
查询文档
// 查找所有用户
User.find()
.then(users => console.log('All users:', users))
.catch(error => console.error('Error finding users:', error));
// 按条件查找
User.findOne({ age: { $gte: 30 } })
.then(user => console.log('User over 30:', user))
.catch(error => console.error('Error finding user:', error));
// 按 ID 查找
User.findById('6123456789abcdef12345678')
.then(user => console.log('User by ID:', user))
.catch(error => console.error('Error finding user by ID:', error));
// 高级查询
User.find()
.where('age').gte(25).lte(40)
.sort('-age')
.select('name email')
.limit(10)
.then(users => console.log('Filtered users:', users))
.catch(error => console.error('Error filtering users:', error));
更新文档
// 按 ID 更新
User.findByIdAndUpdate(
'6123456789abcdef12345678',
{ age: 31 },
{ new: true, runValidators: true }
)
.then(updatedUser => console.log('Updated user:', updatedUser))
.catch(error => console.error('Error updating user:', error));
// 按条件更新
User.updateOne(
{ email: '[email protected]' },
{ $set: { name: 'John Smith' } }
)
.then(result => console.log('Update result:', result))
.catch(error => console.error('Error updating user:', error));
删除文档
// 按 ID 删除
User.findByIdAndDelete('6123456789abcdef12345678')
.then(deletedUser => console.log('Deleted user:', deletedUser))
.catch(error => console.error('Error deleting user:', error));
// 按条件删除
User.deleteMany({ age: { $lt: 25 } })
.then(result => console.log('Deleted users:', result.deletedCount))
.catch(error => console.error('Error deleting users:', error));
5. 中间件(Middleware)
在文档操作前后执行自定义逻辑:
// 保存前的中间件
userSchema.pre('save', function(next) {
// 对密码进行哈希处理
if (this.isModified('password')) {
this.password = bcrypt.hashSync(this.password, 10);
}
next();
});
// 保存后的中间件
userSchema.post('save', function(doc, next) {
console.log('User saved:', doc._id);
next();
});
// 查询后的中间件
userSchema.post('find', function(docs, next) {
console.log(`Returned ${docs.length} users`);
next();
});
6. 虚拟字段(Virtuals)
定义不存储在数据库中的计算字段:
userSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
userSchema.virtual('isAdult').get(function() {
return this.age >= 18;
});
// 使用虚拟字段
User.findOne({ email: '[email protected]' })
.then(user => {
console.log('Full name:', user.fullName);
console.log('Is adult:', user.isAdult);
})
.catch(error => console.error('Error fetching user:', error));
7. 关联(Population)
处理文档间的关系:
// 定义作者模式
const authorSchema = new Schema({
name: String,
country: String
});
// 定义书籍模式
const bookSchema = new Schema({
title: String,
author: {
type: Schema.Types.ObjectId,
ref: 'Author'
}
});
// 关联查询
Book.findOne({ title: 'Mongoose Guide' })
.populate('author', 'name country -_id') // 选择要返回的字段
.then(book => console.log('Book with author:', book))
.catch(error => console.error('Error fetching book:', error));
8. 聚合(Aggregation)
执行复杂的数据处理:
User.aggregate([
// 匹配年龄大于25的用户
{ $match: { age: { $gt: 25 } } },
// 按国家分组并计算每组的平均年龄和用户数
{ $group: {
_id: '$country',
averageAge: { $avg: '$age' },
count: { $sum: 1 }
} },
// 按平均年龄降序排序
{ $sort: { averageAge: -1 } },
// 限制结果数量
{ $limit: 5 }
])
.then(results => console.log('Aggregation results:', results))
.catch(error => console.error('Error in aggregation:', error));
Mongoose 为 MongoDB 提供了强大而灵活的抽象层,使 Node.js 开发者能够更高效地处理数据库操作,同时保持代码的整洁和可维护性。通过合理使用 Schema、Model、验证、中间件等特性,可以构建出健壮的数据库层。