1.23Node.js 中操作 mongodb

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、验证、中间件等特性,可以构建出健壮的数据库层。

相关推荐
托尼沙滩裤2 小时前
【Node】最佳Node.js后端开发模板推荐
node.js
暴怒的代码2 小时前
解决Vue2官网Webpack源码泄露漏洞
前端·webpack·node.js
爱分享的程序员4 小时前
Node.js 实训专栏规划目录
前端·javascript·node.js
Q_Q5110082854 小时前
python的校园兼职系统
开发语言·spring boot·python·django·flask·node.js·php
水冗水孚4 小时前
express使用node-schedule实现定时任务,比如定时清理文件夹中的文件写入日志功能
javascript·node.js·express
雲墨款哥5 小时前
一次由“双重加密”引发的 Node.js 登录失败血案
node.js
代码搬运媛7 小时前
【Node.js 的底层实现机制】从事件驱动到异步 I/O
node.js
CodingPeppa11 小时前
启动hardhat 项目,下载依赖的npm问题
前端·npm·node.js
泓博11 小时前
使用Node.js开发服务端接口
node.js