56

有没有办法在 Mongoose 中删除父级的所有子级,类似于使用 MySQL 的外键?

例如,在 MySQL 中,我会分配一个外键并将其设置为删除时级联。因此,如果我要删除一个客户端,所有应用程序和相关用户也将被删除。

从顶层:

  1. 删除客户端
  2. 删除抽奖
  3. 删除提交

抽奖和提交都有一个 client_id 字段。Submissions 有一个用于sweepstakes_id 和client_id 的字段。

现在,我正在使用以下代码,我觉得必须有更好的方法。

Client.findById(req.params.client_id, function(err, client) {

    if (err)
        return next(new restify.InternalError(err));
    else if (!client)
        return next(new restify.ResourceNotFoundError('The resource you requested could not be found.'));

    // find and remove all associated sweepstakes
    Sweepstakes.find({client_id: client._id}).remove();

    // find and remove all submissions
    Submission.find({client_id: client._id}).remove();

    client.remove();

    res.send({id: req.params.client_id});

});
4

4 回答 4

131

这是 Mongoose'remove' 中间件的主要用例之一。

clientSchema.pre('remove', function(next) {
    // 'this' is the client being removed. Provide callbacks here if you want
    // to be notified of the calls' result.
    Sweepstakes.remove({client_id: this._id}).exec();
    Submission.remove({client_id: this._id}).exec();
    next();
});

这样,当您调用client.remove()此中间件时,会自动调用以清理依赖项。

于 2013-01-16T00:04:38.743 回答
12

如果您的引用以其他方式存储,例如,client有一个数组submission_ids,那么以与接受的答案类似的方式,您可以在 上定义以下内容submissionSchema

submissionSchema.pre('remove', function(next) {
    Client.update(
        { submission_ids : this._id}, 
        { $pull: { submission_ids: this._id } },
        { multi: true })  //if reference exists in multiple documents 
    .exec();
    next();
});

这将从客户端的 引用数组中删除提交的id 。submission.remove()

于 2017-06-03T19:50:23.763 回答
2

这是我发现的另一种方式

submissionSchema.pre('remove', function(next) {
    this.model('Client').remove({ submission_ids: this._id }, next);
    next();
});
于 2018-02-20T17:08:54.183 回答
2

我注意到这里的所有答案都pre分配给了架构,而不是post.

我的解决方案是这样的:(使用猫鼬6+)

ClientSchema.post("remove", async function(res, next) { 
    await Sweepstakes.deleteMany({ client_id: this._id });
    await Submission.deleteMany({ client_id: this._id });
    next();
});

根据定义 post 在流程结束后执行pre => process => post

现在,您可能想知道这与此处提供的其他解决方案有何不同。如果找不到服务器错误或该客户端的 ID 怎么办?在 pre 上,它会在删除过程sweeptakes开始submissions之前删除所有client. 因此,如果出现错误,最好将其他文档级联删除一次,client否则主文档会被删除。

async 和 await 在这里是可选的。但是,它对大数据很重要。这样如果删除进度仍在进行,用户就不会得到那些“将被删除”的级联文档数据。

最后,我可能是错的,希望这对他们的代码有所帮助。

于 2021-10-20T21:44:25.993 回答