前端玩数据库 👏 MongoDB/Mongoose 入门指南(下)

一、前言

在信息化时代,数据无疑已成为企业最宝贵的资产之一。随着数据量的激增和数据类型的多样化,传统关系型数据库在处理某些类型的数据时显得捉襟见肘。正是在这样的背景下,非关系型数据库(NoSQL)应运而生,以其灵活的数据模型、卓越的扩展性和强大的性能处理能力,迅速崛起成为现代应用开发的新宠。MongoDB,作为 NoSQL 数据库的佼佼者,以其文档导向的存储方式和强大的查询语言,为开发者提供了一个高效、易用的数据处理平台。而 Mongoose,作为 Node.js 环境下 MongoDB 的 ODM(对象数据建模)库,进一步简化了数据库操作,让开发者能够更加专注于业务逻辑的实现。本指南旨在提供一个全面的 MongoDBMongoose 使用入门教程。文章分为上下两篇,当前为"下篇"内容:

二、Mongoose 使用

上篇主要介绍了 MondoDB 云端托管的安装方式、Mongoose 的基础知识以及 Mongoose 中所有内容起点"模型定义"。在完成这些准备工作后,我们就要开始真正运用 Mongoose 进行数据库操作了。

注意点及说明:

  1. 尽量避免使用箭头函数,因为使用箭头时 this 将无法访问到正确内容!
  2. 下文仅包含一些较为常用内容,如需更多完整内容请详见 👉 官方文档

2.1 增删改查

新增

javascript 复制代码
await MyModel.create(docs, options); 
// 新增一条:await MyModel.create({ name: 'Tim' });
// 新增多条:await MyModel.create([{ name: 'Tim' }, { name: 'Tom' }]);

await MyModel.create(docs, options); 
// 新增多条:await MyModel.insertMany([{ name: 'Tim' }, { name: 'Tom' }]);

删除

javascript 复制代码
await MyModel.deleteOne(conditions, options); // returns {deletedCount: 1}
await MyModel.deleteMany(conditions, options); // returns {deletedCount: x}
await MyModel.findByIdAndDelete(id, options);
await MyModel.findOneAndDelete(conditions, options) 

更新

javascript 复制代码
await MyModel.updateMany(conditions, update, options);
await MyModel.updateOne(conditions, update, options);
await MyModel.findByIdAndUpdate(id, update, options);
await MyModel.findOneAndReplace(conditions, replacement, options) 
await MyModel.findOneAndUpdate(conditions, update, options) 

查找

javascript 复制代码
await MyModel.find(conditions, projection); // 第二个参数指定返回字段,支持多种类型传入,例如字符串形式 await MyModel.find({ name: /john/i }, 'name friends')
await MyModel.findOne(conditions, projection, options);
await MyModel.findById(id, projection, options);

2.2 进阶查询

2.2.1 查询条件

  1. 查询对象:Model.find({ field: value })
  2. 正则表达式:Model.find({ name: /regexpattern/i })
  3. 链式查询:Model.find().where('age').gte(18).lt(65)
  4. 操作符:Model.find({ age: { $gt: 18, $lt: 65 } }),Mongoose 支持 MongoDB 的查询操作符,常用的查询操作符有:

2.2.2 排序&分页

对查询结果进行排序和限制返回的文档数量。

javascript 复制代码
Model.find().sort({ field: -1 }).limit(10);

用于分页,跳过一定数量的文档,并限制返回的文档数量。

javascript 复制代码
Model.find().skip(10).limit(10).exec(callback);  // skip = (页码-1)*每页数

2.2.3 查询聚合

Mongoose 聚合框架提供了一组丰富的操作符,允许你在 MongoDB 中执行复杂的数据处理和聚合操作。这些操作符基于 MongoDB 的聚合管道,可以将数据转换和处理成几乎任何形式,您可以使用聚合操作来:

  • 将多个文档中的值组合在一起。
  • 对分组数据执行操作,返回单一结果。
  • 分析一段时间内的数据变化。

更多内容查看 👉 Mongoose 文档MongoDB 文档,示例如下:

javascript 复制代码
// Find the max balance of all accounts
const res = await Users.aggregate([
  { $group: { _id: null, maxBalance: { $max: '$balance' }}},
  { $project: { _id: 0, maxBalance: 1 }}
]);
console.log(res); // [ { maxBalance: 98000 } ]

// Or use the aggregation pipeline builder.
const res = await Users.aggregate().
  group({ _id: null, maxBalance: { $max: '$balance' } }).
  project('-id maxBalance').
  exec();
console.log(res); // [ { maxBalance: 98 } ]

2.3 中间件

Mongoose 中间件有 4 种类型:文档中间件、模型中间件、聚合中间件和查询中间件,通过这些中间件我们可以文档保存、验证等生命周期中插入自定义的逻辑。所有中间件类型都支持前置(pre)和后置(post)钩子,并且要注意你必须在调用 mongoose.model() 之前添加所有中间件。

javascript 复制代码
schema.pre('save', function(next) {
  // 执行一些操作
  next();
});

schema.pre('save', function() {
  // 返回一个 Promise 或使用 async/await
  return asyncFunc().then(() => {});
});

schema.post('save', function(doc) {
  console.log('文档已保存', doc._id);
});

schema.post('save', function(doc, next) {
  setTimeout(function() {
    console.log('post1');
    next();
  }, 10);
});

2.3.1 文档中间件

文档中间件中的this指向当前 document,支持以下文档操作:

  • init:初始化钩子。
  • validate:验证钩子。
  • save:保存钩子。
  • remove:删除钩子。
javascript 复制代码
tourSchema.pre("save", function (next) {
  this.slug = slugify(this.name, { lower: true });
  next();
});

2.3.2 模型中间件

文档中间件中的this指向当前 model,支持以下模型操作:

  • bulkWrite
  • createCollection
  • insertMany

注意,不要将模型中间件(model middleware)和文档中间件(document middleware)混淆。模型中间件与模型类的静态函数相关联,不需要创建类实例就可以调用。文档中间件与模型中间件不同,文档中间件与模型类的方法相关联,需要通过类实例来调用。

2.3.2 聚合中间件

聚合中间件适用于 MyModel.aggregate()。当聚合对象调用 exec() 时,聚合中间件就会执行。在聚合中间件中this指的是聚合对象。

javascript 复制代码
tourSchema.pre("aggregate", function (next) {
  this.pipeline().unshift({ $match: { secretTour: { $ne: true } } });
  next();
});

2.3.2 查询中间件

在查询中间件函数中,this指的是当前查询 query,查询中间件支持以下查询操作:

  • count
  • countDocuments
  • deleteMany
  • deleteOne
  • estimatedDocumentCount
  • find
  • findOne
  • findOneAndDelete
  • findOneAndReplace
  • findOneAndUpdate
  • replaceOne
  • updateOne
  • updateMany
  • validate
javascript 复制代码
tourSchema.pre(/^find/, function (next) {
  this.find({ secretTour: { $ne: true } });
  this.start = Date.now();
  next();
});
tourSchema.post(/^find/, function (docs, next) {
  console.log(`Query took ${Date.now() - this.start} milliseconds!`);
  next();
});

三、总结

文本源码 👉 nodejs-learn-natours

本文是指南的下篇-"实践篇",主要介绍了 Mongoose 的基础增删改查、进阶查询和中间件的内容。如想要了解前期准备工作,如MondoDB 云端托管的安装方式、Mongoose 的基础知识以及 Mongoose 中所有内容起点"模型定义"等,请跳转阅读《前端玩数据库 👏 MongoDB/Mongoose 入门指南(上)》。希望本文能够作为您使用 Mongoose 的起点,助您在 Node.js 和 MongoDB 的世界中更进一步,另外请不要忘记官方文档一定是最好的资料,多多阅读。

相关推荐
LaughingZhu12 分钟前
PH热榜 | 2025-04-09
前端·数据库·人工智能·mysql·开源
枫super25 分钟前
Day-03 前端 Web-Vue & Axios 基础
前端·javascript·vue.js
程序猿chen1 小时前
Vue.js组件安全工程化演进:从防御体系构建到安全性能融合
前端·vue.js·安全·面试·前端框架·跳槽·安全架构
你也来冲浪吗1 小时前
MD编辑器用法讲解
前端
小小小小宇1 小时前
十万字总结所有React hooks(含简单原理)
前端
MariaH1 小时前
MySQL数据库DQL
前端
Enjoy10241 小时前
v8垃圾回收机制
前端
Georgewu1 小时前
【HarmonyOS 5】敏感信息本地存储详解
前端·harmonyos
_Le_1 小时前
css 小师系列:一种新的影响样式优先级的方式😍
前端·css
wordbaby1 小时前
从前端视角看 MCP:解锁 LLM 工具调用与结构化交互
前端