Mongoose 插件使用 find() 过滤数组文档和根文档中的软删除,并对数组文档和根文档执行软删除

问题描述 投票:0回答:1

实现软删除数组文档和根文档的 Mongoose 插件以及过滤软删除数组文档和根文档。

我正在开发一个 Mongoose 插件,用于在 MongoDB 数据库中使用 find() 处理软删除和软删除项目的过滤。该插件需要:

  1. 自动过滤掉 find() 查询中的软删除文档和嵌套数组项。
  2. 提供一种对顶级文档和嵌套数组项执行软删除的方法。
  3. 允许选择在需要时在查询中包含软删除项目。

我的主要挑战是:

  • 确保预查找挂钩有效过滤顶级和嵌套软删除项目。
  • 实现适用于各种文档结构的灵活软删除方法。
  • 处理显示软删除项目的选项,而不会使查询过程复杂化。

我特别感兴趣的是:

  1. 处理嵌套文档和数组。

任何指导或示例模式将不胜感激!

Data  :

 {
      "_id": {
        "$oid": "66c883a5e6ddbf5f720ae1b6"
      },
      "name": "Some Name",
      "email": "[email protected]",
      "age": 48,
      "nestedArr": [
        {
          "id": 7032086,
          "value": "apple0",
          "isDeleted": false
        },
        {
          "id": 4086837,
          "value": "apple0",
          "isDeleted": true
        },
        {
          "id": 6683277,
          "value": "apple0",
          "isDeleted": false
        },
        {
          "id": 2870389,
          "value": "apple0",
          "isDeleted": true
        }
      ],
      "isDeleted": true,
    }
javascript node.js mongodb mongoose mongoose-plugins
1个回答
0
投票

以下逻辑是为了了解预钩子猫鼬模式中

projection
filter
的机制,以便创建软删除插件:

const mongoose = require("mongoose");

// Define User Schema
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 2,
    maxlength: 50,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
  nestedArr: [
    {
      id: Number,
      value: String,
      isDeleted: Boolean,
    },
  ],

  isDeleted: Boolean,
});

// User Plugin
function softDeletePlugin(schema, options) {
  schema.add({
    isDeleted: {
      type: Boolean,
      required: true,
      default: false,
    },
  });

  schema.pre("find", function (next) {
    const filter = this.getQuery();
    const options = this.getOptions();

    //In case we need to show soft deleted items  (We can also put in getOptions() but I have put in filter)
    if (filter.showSoftDeleted) {
      delete filter["showSoftDeleted"];
      this.setQuery(filter);
      return next();
    }

    // Filter out root (top-level) documents where isDeleted is true
    if (!filter.hasOwnProperty("isDeleted")) {
      filter.isDeleted = { $ne: true };
    }

    // For Array documents. Using $filter will bring all matching records unlike $elemMatch which returns 1st matching result
    if (!options.projection) {
      options.projection = {};
    }
    options.projection.nestedArr = {
      $filter: {
        input: "$nestedArr",
        as: "item",
        cond: { $ne: ["$$item.isDeleted", true] },
      },
    };

    this.setQuery(filter);
    this.setOptions(options);

    return next();
  });

  // Static soft delete method
  schema.statics.softDelete = function (
    conditionFilter,
    nestedRecord = false,
    nestedRecordKey = "nestedArr"
  ) {
    let softDeleteInstance;
    if (nestedRecord) {
      const updateQuery = {
        $set: {
          [`${nestedRecordKey}.$[elem].isDeleted`]: true,
        },
      };

      softDeleteInstance = this.updateMany(conditionFilter, updateQuery, {
        arrayFilters: [
          { [`elem._id`]: conditionFilter[`${nestedRecordKey}._id`] },
        ],
      }).exec();
    }

    //check if _id is given to soft delete root document
    //update root documents (top-level documents) if required to delete.
    if (conditionFilter._id) {
      const updateQuery = {
        $set: {
          isDeleted: true,
        },
      };
      softDeleteInstance = this.updateMany(conditionFilter, updateQuery).exec();
    }

    return softDeleteInstance;
  };
}

// Apply the plugin to the schema
userSchema.plugin(softDeletePlugin);

// User model
const User = mongoose.model("User", userSchema);

// Connect to MongoDB
mongoose
  .connect("mongodb://localhost/userdb")
  .then(() => console.log("Connected to MongoDB"))
  .catch((err) => console.error("Could not connect to MongoDB", err));

// How to use :

//soft deletes only array documents
User.softDelete(
  {
    "nestedArr.id": 4086837,
  },
  true
).then(() => console.log("Soft deleted"));

// to soft delete both root & array documents
User.softDelete(
  {
    _id: "66c883a5e6ddbf5f720ae1b6",
    "nestedArr.id": 4086837,
  },
  true
).then(() => console.log("Soft deleted"));

User.find({})
  .lean()
  .then((data) => {
    console.log(data);
  });

/*
  1st argument : conditionFilter
  2nd argument : projection
  3rd argument : to provide Options -> getOptions() in mongoose schema

  // showSoftDeleted to include soft deleted items
  User.find({showSoftDeleted : true}, null, {});

  */
© www.soinside.com 2019 - 2024. All rights reserved.