You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发Mongoose软删除插件:过滤与处理根文档及嵌套数组文档

实现支持根文档与嵌套数组的Mongoose软删除插件

一、核心插件实现

以下是满足需求的Mongoose软删除插件代码,包含自动过滤、软删除方法及查询控制功能:

const mongoose = require('mongoose');

const softDeletePlugin = (schema, options = {}) => {
  // 为根文档添加软删除标识字段,默认未删除
  schema.add({
    isDeleted: { type: Boolean, default: false, index: true }
  });

  // 配置需要处理的嵌套数组字段(需提前指定)
  const nestedArrayFields = options.nestedArrayFields || [];

  // Pre-find钩子:自动过滤已删除条目
  schema.pre(['find', 'findOne', 'findById'], function(next) {
    const query = this.getQuery();

    // 若查询包含includeDeleted: true,跳过所有过滤逻辑
    if (query.includeDeleted) {
      delete query.includeDeleted;
      return next();
    }

    // 过滤根文档:仅当用户未显式指定isDeleted条件时,排除已删除文档
    if (!query.isDeleted) {
      this.where({ isDeleted: { $ne: true } });
    }

    // 过滤嵌套数组:仅返回数组中未删除的元素
    if (nestedArrayFields.length > 0) {
      // 保留用户指定的投影字段,避免覆盖原有需求
      const projectStage = { ...this.getProjection() };
      nestedArrayFields.forEach(field => {
        projectStage[field] = {
          $filter: {
            input: `$${field}`,
            as: 'item',
            cond: { $eq: ['$$item.isDeleted', false] }
          }
        };
      });

      // 将find查询转换为聚合管道,实现数组元素过滤
      this.aggregate([
        { $match: this.getQuery() },
        { $project: projectStage }
      ]);
    }

    next();
  });

  // 根文档软删除实例方法
  schema.methods.softDelete = async function() {
    this.isDeleted = true;
    return this.save();
  };

  // 嵌套数组条目软删除静态方法
  schema.statics.softDeleteNestedItem = async function(docId, arrayField, itemKey, itemValue) {
    return this.updateOne(
      { _id: docId, [`${arrayField}.${itemKey}`]: itemValue },
      { $set: { [`${arrayField}.$.isDeleted`]: true } }
    );
  };

  // 根文档恢复实例方法
  schema.methods.restore = async function() {
    this.isDeleted = false;
    return this.save();
  };

  // 嵌套数组条目恢复静态方法
  schema.statics.restoreNestedItem = async function(docId, arrayField, itemKey, itemValue) {
    return this.updateOne(
      { _id: docId, [`${arrayField}.${itemKey}`]: itemValue },
      { $set: { [`${arrayField}.$.isDeleted`]: false } }
    );
  };
};

module.exports = softDeletePlugin;

二、核心功能说明

1. 自动过滤逻辑

  • 根文档过滤:通过pre-find钩子自动添加isDeleted: { $ne: true }条件,排除已软删除的根文档;若用户显式指定isDeleted查询条件,插件不会覆盖。
  • 嵌套数组过滤:利用MongoDB的$filter聚合操作,在查询时仅保留数组中isDeleted: false的元素,需在插件初始化时指定需要处理的数组字段。

2. 软删除与恢复方法

  • 根文档:通过实例方法softDelete()和restore()直接修改文档的isDeleted状态并保存。
  • 嵌套数组:通过静态方法softDeleteNestedItem()和restoreNestedItem(),根据数组元素的唯一标识(如id)定位并修改对应条目的状态。

3. 包含已删除条目查询

在查询时添加includeDeleted: true参数,插件会跳过所有过滤逻辑,返回包含已软删除的根文档和嵌套数组条目。

三、使用示例

1. 定义Schema并应用插件

const userSchema = new mongoose.Schema({
  name: String,
  email: String,
  age: Number,
  nestedArr: [{
    id: Number,
    value: String,
    isDeleted: { type: Boolean, default: false }
  }]
});

// 应用插件,指定需要处理的嵌套数组字段
userSchema.plugin(softDeletePlugin, { nestedArrayFields: ['nestedArr'] });

const User = mongoose.model('User', userSchema);

2. 基本查询(自动过滤已删除项)

// 查询所有未删除的用户,且nestedArr仅包含未删除的条目
const activeUsers = await User.find();

3. 查询包含已删除项

// 查询所有用户(包括已删除的根文档),返回nestedArr的所有条目
const allUsers = await User.find({ includeDeleted: true });

4. 软删除根文档

const user = await User.findById('66c883a5e6ddbf5f720ae1b6');
await user.softDelete();

5. 软删除嵌套数组条目

// 删除nestedArr中id为4086837的条目
await User.softDeleteNestedItem('66c883a5e6ddbf5f720ae1b6', 'nestedArr', 'id', 4086837);

6. 恢复操作

// 恢复根文档(需先查询到已删除的文档)
const deletedUser = await User.findById('66c883a5e6ddbf5f720ae1b6', { includeDeleted: true });
await deletedUser.restore();

// 恢复嵌套数组条目
await User.restoreNestedItem('66c883a5e6ddbf5f720ae1b6', 'nestedArr', 'id', 4086837);

四、注意事项

  • 索引优化:为isDeleted字段添加索引,提升根文档过滤的查询效率;若需保障未删除文档的字段唯一性,可添加复合索引(如{ email: 1, isDeleted: 1 })。
  • 嵌套数组配置:需明确指定需要处理的嵌套数组字段,避免误处理不需要软删除的数组。
  • 聚合转换限制:当查询转换为聚合管道时,部分mongoose链式方法(如populate)无法直接使用,需改用聚合的$lookup实现关联查询。

内容的提问来源于stack exchange,提问作者mongoPioneer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:28:17