Express pre remove 触发另一个 pre remove on remove

Posted

技术标签:

【中文标题】Express pre remove 触发另一个 pre remove on remove【英文标题】:Express pre remove triggers another pre remove on remove 【发布时间】:2021-08-03 06:16:05 【问题描述】:

假设我有 4 个这样的模型:

┌────────────┐      ┌────────────┐
│    User    │      │    Goal    │
├────────────┤ 1    ├────────────┤ 1
│    _id     │◄──┐  │    _id     │◄──┐
└────────────┘   └──┤  ref_user  │   │
                1..*└────────────┘   │
                                     │
┌───────────┐     ┌───────────────┐  │
│   Date    │     │     Data      │  │
├───────────┤ 1   ├───────────────┤  │
│ _id: date │◄─┐  │     _id       │  │
└───────────┘  └──┤    ref_date   │  │
                1 │    ref_goal   ├──┘
                  └───────────────┘ *

我在删除数据时创建了一个pre remove,它会自动删除关联的日期。

DataSchema.pre('remove', async function (next) 
    try 
        await DateModel.findByIdAndRemove(this.ref_date);
        console.log("Date removed");
        next();
     catch (err) 
        console.log(err);
        next(err);
    
);

我面临的问题是,当我删除一个目标时,我希望删除所有关联的数据(它有效)但我希望 DataModel.remove 触发其pre remove 并删除其日期。 从逻辑的角度来看,当删除目标中pre remove 钩子上的数据时,这也应该触发数据中的pre remove,因为删除了数据数据。为什么从另一个 pre remove 钩子中删除数据时不会触发它的 pre remove

从 Goal 中,我可以检索数据数组,但我不认为循环遍历数组并逐个删除日期是一个好习惯。

有没有办法触发从数据中的预删除,从目标的预删除?或者一种从数据数组中删除所有日期的方法?

ps:在未来,我想要在删除用户时再次做同样的事情(删除其所有目标,即删除所有数据和日期)。

编辑:

按照要求,他是我的目标,预移除钩子

GoalSchema.pre('remove', async function (next) 
    try 
        await DataModel.deleteMany( 'ref_goal': this._id );
        console.log("Data removed");
        next();
     catch (err) 
        console.log(err);
        next(err);
    
);

我尝试了deleteManyremove 等,但似乎都没有触发Data 预删除钩子

环境:

"express": "^4.17.1",
"mongoose": "^5.12.2",

【问题讨论】:

你能显示目标pre remove钩子吗? @CuongLeNgoc 完成,我更新了我的问题 你使用的是哪个版本的猫鼬和快递? 并且还添加了日期数据和目标的模式/模型定义。为什么不在数据方案中将日期定义为嵌套模型。如图所示? mongoosejs.com/docs/subdocs.html @Shasak 我是 react-native 的新手,我不知道嵌套模型。但是,如果我想删除一个用户,问题是一样的,我希望删除它的所有目标,以及目标的所有数据。在未来,我的shema会更复杂,我想了解为什么pre remove hook不会触发另一个schema pre remove hook 【参考方案1】:

您当前的代码有两个问题:

    您正在 data 架构上注册 remove 挂钩:

    DataSchema.pre('remove', ...)
    

    当你是goalremove钩子的回调triggers一个deleteMany中间件:

    await DataModel.deleteMany(...)
    

    因此dataremove 挂钩未触发。

    现在,您提到您尝试了其他功能,例如remove,这将我们带到了第二期:

    您在文档上注册 remove 挂钩(这是默认设置),同时在模型上执行功能。

    在docs 上查看此说明:

    注意:如果你指定schema.pre('remove'),Mongoose会注册这个 doc.remove() 默认的中间件。如果你想要你的中间件 要在 Query.remove() 上运行,请使用 schema.pre('remove', query: true, document: false , fn)

    相关的也是这个解释:

    您可以将选项传递给Schema.pre()Schema.post() 进行切换 Mongoose 是否将您的 remove() 钩子称为 Document.remove()Model.remove()。注意这里需要同时设置documentquery 传递对象中的属性:

    // Only document middleware 
    schema.pre('remove',  document: true, query: false , function()    
       console.log('Removing doc!'); 
    );
    
    // Only query middleware. This will get called when you do `Model.remove()` 
    // but not `doc.remove()`. 
    schema.pre('remove',  query: true, document: false , function()   
       console.log('Removing!'); 
    );
    

我认为以下应该可行:

const onRemoveData = async function (next) 
   try 
        let removed = [this];
        if (this instanceof mongoose.Query) 
           removed = await this.model.find(this.getQuery());
        
        removed.forEach(function(doc) 
            await DateModel.findByIdAndRemove(doc.ref_date);
            console.log("Date removed");
        );
        next();
     catch (err) 
        console.log(err);
        next(err);
    

DataSchema.pre(['remove', 'deleteMany'],  document: true, query: false, onRemoveData);
DataSchema.pre(['remove', 'deleteMany'],  document: false, query: true, onRemoveData);

【讨论】:

谢谢,现在数据预删除已触发,但 this 现在是 Query,我不知道如何在数据挂钩中使用 this.ref_date onRemoveData 函数中,this 是一个Query ...。如何访问this.ref_date 你是对的,正如文档所指出的那样:“如果您需要访问将要更新的文档,则需要对该文档执行显式查询。”我编辑了代码以使其正常工作,请尝试一下。 非常感谢!您的更正工作几乎完美,它只删除了一个Date,我认为是因为this.model.findOne。我尝试使用this.modal.find,但它不会删除任何Date。我阅读了文档,它只谈论this.model.findOne 哦,对了,find 返回一个数组。我又编辑了,请试一试(注意我还附上了[this])。

以上是关于Express pre remove 触发另一个 pre remove on remove的主要内容,如果未能解决你的问题,请参考以下文章

如何从另一个框架向 Ember 触发事件

[leetcode]203. Remove Linked List Elements链表中删除节点

错误:子进程 已安装 pre-removal 脚本 返回了错误号 1

E. Segments Removal(优先队列&set)

82.Remove Duplicates from Sorted List II

使用express框架和mongoose在MongoDB删除数据