实现软删除数组文档和根文档的 Mongoose 插件以及过滤软删除数组文档和根文档。
我正在开发一个 Mongoose 插件,用于在 MongoDB 数据库中使用 find() 处理软删除和软删除项目的过滤。该插件需要:
我的主要挑战是:
我特别感兴趣的是:
任何指导或示例模式将不胜感激!
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,
}
以下逻辑是为了了解预钩子猫鼬模式中
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, {});
*/