前端玩数据库 👏 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 的世界中更进一步,另外请不要忘记官方文档一定是最好的资料,多多阅读。

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax