not*_*not 5 middleware mongoose mongodb mongoose-deleteone
随着删除在猫鼬 5.7.13 中被弃用,我想改用 deleteOne。我需要获取已删除文档的 id,以便我可以在级联中删除其他集合中的进一步相关文档。我认为 pre 中间件挂钩上下文中的“this”是指已删除的文档,但它只是一个空对象。是否有一个规范的工作示例?我目前仍在使用 5.7.12 - 这会有所不同吗?
这是我目前正在使用的代码。问题是我无法在开始时获取 projectId,因为引用完全为空。在 post 而不是 pre 上执行此操作,或将选项切换为在查询上运行而不是文档都会产生相同的结果。
ProjectSchema.pre("deleteOne", {document:true}, (next) => {
const projectId = this._id;
ListModel.find({parentProject:projectId}, (err, lists) => {
if(err){
console.log("error cascading project delete to lists", {err});
}
lists.map(list => {
ListModel.deleteOne({_id:list._id}, (err, result) => {
if(err) {
console.log("error on project delete cascade", {err});
}
});
});
});
});Run Code Online (Sandbox Code Playgroud)
Ale*_*lex 10
这取决于您是在文档还是模型上调用 deleteOne。后者只是没有文件可以绑定它。
前者按您的预期为您提供文档:
const project = await ProjectModel.findOne();
project.deleteOne();
Run Code Online (Sandbox Code Playgroud)
后者为您提供查询。_id查询中没有,但它有this.op例如,在这个中间件中将是“deleteOne”:
await ProjectModel.deleteOne();
Run Code Online (Sandbox Code Playgroud)
在这种情况下获取文档 ID 的唯一方法是确保在查询中提供它:
await ProjectModel.deleteOne({_id: "alex"});
Run Code Online (Sandbox Code Playgroud)
然后你可以从过滤器的中间件中获取它:
const projectId = this.getFilter()["_id"]
Run Code Online (Sandbox Code Playgroud)
您可以query: false在中间件的第二个参数中指定,以确保在模型上调用 deleteOne 时不会调用它。所以你能做的最好的事情是:
ProjectSchema.pre("deleteOne", {document:true, query: false}, (next) => {
const projectId = this._id;
....
});
ProjectSchema.pre("deleteOne", {document:false, query: true}, (next) => {
const projectId = this.getFilter()["_id"];
if (typeof projectId === "undefined") {
// no way to make cascade deletion since there is no _id
// in the delete query
// I would throw an exception, but it's up to you how to deal with it
// to ensure data integrity
}
});
Run Code Online (Sandbox Code Playgroud)
请看一下v5.7.12上对应的测试:https : //github.com/Automattic/mongoose/blob/5.7.12/test/model.middleware.test.js#L436
在mongoose 文档中,它说“Model.deleteOne() 不会触发 pre('remove') 或 post('remove') 挂钩。”
如果您可以使用findByIdAndDelete重构删除操作,则有解决方案,它会触发findOneAndDelete中间件,
所以我们可以将这个中间件添加到项目架构中。
项目型号:
const mongoose = require("mongoose");
const ProjectChild = require("./projectChild");
const ProjectSchema = new mongoose.Schema({
name: String
});
ProjectSchema.post("findOneAndDelete", async function(doc) {
console.log(doc);
if (doc) {
const deleteResult = await ProjectChild.deleteMany({
parentProject: doc._id
});
console.log("Child delete result: ", deleteResult);
}
});
module.exports = mongoose.model("Project", ProjectSchema);
Run Code Online (Sandbox Code Playgroud)
项目子模型:
const mongoose = require("mongoose");
const projectChildSchema = new mongoose.Schema({
name: String,
parentProject: {
type: mongoose.Schema.Types.ObjectId,
ref: "Project"
}
});
module.exports = mongoose.model("ProjectChild", projectChildSchema);
Run Code Online (Sandbox Code Playgroud)
我创建了一个这样的项目:
{
"_id": "5dea699cb10c442260245abf",
"name": "Project 1",
"__v": 0
}
Run Code Online (Sandbox Code Playgroud)
并为此项目创建了 2 个项目子项目:
儿童 1
{
"_id": "5dea69c7b10c442260245ac0",
"name": "Child 1 (project 1)",
"parentProject": "5dea699cb10c442260245abf",
"__v": 0
}
Run Code Online (Sandbox Code Playgroud)
儿童 2
{
"_id": "5dea69e8b10c442260245ac1",
"name": "Child 2 (project 1)",
"parentProject": "5dea699cb10c442260245abf",
"__v": 0
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个示例路由来按项目 ID 删除项目,如下所示:
router.delete("/project/:id", async (req, res) => {
const result = await Project.findByIdAndDelete(req.params.id);
res.send(result);
});
Run Code Online (Sandbox Code Playgroud)
当我向该路由发送 DELETE 请求时,我们在控制台中看到以下信息:
console.log(doc);
{ _id: 5dea699cb10c442260245abf, name: 'Project 1', __v: 0 }
Run Code Online (Sandbox Code Playgroud)
console.log("Child delete result: ", deleteResult);
Child delete result: { n: 2, ok: 1, deletedCount: 2 }
Run Code Online (Sandbox Code Playgroud)
因此,当我们删除项目时,我们可以删除该项目的 2 个子项目。
作为替代方案,您也可以使用findOneAndRemove,它会触发 findOneAndRemove 后中间件。
因此,在 ProjectSchema 中,我们像这样替换后中间件:
ProjectSchema.post("findOneAndRemove", async function(doc) {
console.log(doc);
if (doc) {
const deleteResult = await ProjectChild.deleteMany({
parentProject: doc._id
});
console.log("Child delete result: ", deleteResult);
}
});
Run Code Online (Sandbox Code Playgroud)
当我们使用 findOneAndRemove 操作时,结果将与第一个替代方案相同:
const result = await Project.findOneAndRemove({ _id: req.params.id });
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4051 次 |
| 最近记录: |