简介:本文通过Node.js环境下的MongoDB原生驱动与Mongoose ODM对比,详细讲解数据库连接、数据模型定义、CRUD操作及错误处理,帮助开发者快速掌握非关系型数据库开发核心技能。
在Node.js项目中集成MongoDB需要完成三步配置:
npm install mongodbnpm install mongoose.env文件中
# .env示例MONGODB_URI=mongodb://localhost:27017/testdb
作为文档型数据库,MongoDB具有以下显著特征:
Mongoose作为ODM(对象文档映射)工具,通过Schema定义数据结构,Model作为文档构造函数,实现:
const { MongoClient } = require('mongodb');async function connect() {const client = new MongoClient(process.env.MONGODB_URI);try {await client.connect();console.log('Connected to MongoDB');return client;} catch (err) {console.error('Connection error:', err);throw err;}}
最佳实践:
async function insertUser(client, userData) {const db = client.db();const result = await db.collection('users').insertOne(userData);console.log(`Inserted document with _id: ${result.insertedId}`);return result;}
// 基础查询async function findUsers(client, query = {}) {return await client.db().collection('users').find(query).toArray();}// 聚合查询示例async function getUserStats(client) {return await client.db().collection('users').aggregate([{ $match: { status: 'active' } },{ $group: {_id: '$role',count: { $sum: 1 },avgAge: { $avg: '$age' }}}]).toArray();}
async function updateUser(client, userId, updates) {const result = await client.db().collection('users').updateOne({ _id: new ObjectId(userId) },{ $set: updates },{ upsert: false });return result.modifiedCount > 0;}
const mongoose = require('mongoose');const userSchema = new mongoose.Schema({username: {type: String,required: [true, '用户名不能为空'],unique: true,trim: true,minlength: [3, '用户名至少3个字符']},email: {type: String,validate: {validator: v => /^\S+@\S+\.\S+$/.test(v),message: props => `${props.value} 不是有效的邮箱地址`}},createdAt: {type: Date,default: Date.now,select: false // 默认不返回}});// 虚拟属性userSchema.virtual('fullName').get(function() {return `${this.firstName} ${this.lastName}`;});// 实例方法userSchema.methods.greet = function() {console.log(`Hello, ${this.username}`);};// 静态方法userSchema.statics.findByRole = function(role) {return this.find({ role });};const User = mongoose.model('User', userSchema);
userSchema.pre('save', async function(next) {if (this.isModified('password')) {this.password = await bcrypt.hash(this.password, 10);}next();});// 文档中间件userSchema.pre('findOneAndUpdate', function() {const update = this.getUpdate();if (update.$set && update.$set.password) {update.$set.password = await bcrypt.hash(update.$set.password, 10);}});
userSchema.post('save', function(doc) {console.log(`${doc.username} 已被保存`);});
async function transferFunds(fromId, toId, amount) {const session = await mongoose.startSession();session.startTransaction();try {const opts = { session };const fromUser = await User.findByIdAndUpdate(fromId,{ $inc: { balance: -amount } },opts);const toUser = await User.findByIdAndUpdate(toId,{ $inc: { balance: amount } },opts);await session.commitTransaction();return true;} catch (err) {await session.abortTransaction();throw err;} finally {session.endSession();}}
// 创建索引userSchema.index({ username: 1 }, { unique: true });userSchema.index({location: '2dsphere',createdAt: -1});// 复合索引示例userSchema.index({role: 1,status: 1,lastLogin: -1});
explain()分析查询性能$where操作符(无法使用索引)bulkWrite()
mongoose.connect(process.env.MONGODB_URI, {poolSize: 10, // 默认5socketTimeoutMS: 30000,connectTimeoutMS: 10000,serverSelectionTimeoutMS: 5000,maxPoolSize: 50, // 最大连接数minPoolSize: 5, // 最小连接数retryWrites: true,retryReads: true});
slowms参数)mongostat和mongotop输出分片集群部署:
安全实践:
监控体系:
通过本文的系统学习,开发者可以全面掌握Node.js环境下MongoDB和Mongoose的核心开发技术。从基础连接管理到高级事务处理,从性能优化到安全实践,每个环节都提供了可落地的解决方案。建议开发者在实际项目中逐步实践这些技术点,并结合MongoDB官方文档进行深入学习。