Mongoose中的层叠样式删除

kmb7vmvb  于 2023-10-19  发布在  Go
关注(0)|答案(6)|浏览(106)

有没有一种方法可以删除Mongoose中父对象的所有子对象,类似于使用MySQL外键?
例如,在MySQL中,我会分配一个外键并将其设置为cascade on delete。因此,如果我删除一个客户端,所有的应用程序和相关的用户也将被删除。
从顶层:
1.删除客户端
1.删除抽奖
1.删除提交
抽奖和提交都有一个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});

});
cl25kdpy

cl25kdpy1#

这是Mongoose的'remove'middleware的主要用例之一。

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()时,这个中间件会自动被调用来清理依赖项。

7vux5j2d

7vux5j2d2#

如果你的引用是以其他方式存储的,比如说,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();
});

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

6yoyoihd

6yoyoihd3#

我注意到这里所有的答案都有一个pre分配给模式,而不是post
我的解决方案是这样的(使用mongoose 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上,它会在client的删除过程开始之前删除所有sweeptakessubmissions。因此,如果出现错误,最好在client或主文档被删除后级联删除其他文档。
在这里,alert和await是可选的。但是,这对大数据很重要。这样,如果删除进程仍在进行,用户就不会得到那些“将要被删除”的级联文档数据。
最后,我可能是错的,希望这对代码中的某个人有所帮助。

rjzwgtxy

rjzwgtxy4#

这是我发现的另一种方法

submissionSchema.pre('remove', function(next) {
    this.model('Client').remove({ submission_ids: this._id }, next);
    next();
});
hjzp0vay

hjzp0vay5#

型号

const orderSchema = new mongoose.Schema({
    // Множество экземпляров --> []
    orderItems: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'OrderItem',
        required: true
    }],
    ...
    ...
});

密码(* 可选 *)

const asyncHandler = fn => (req, res, next) =>
  Promise
    .resolve(fn(req, res, next))
    .catch(next)

module.exports = asyncHandler;

控制器

const asyncHandler = require("../middleware/asyncErrHandler.middleware");

// **Models**
const Order = require('../models/order.mongo');
const OrderItem = require('../models/order-item.mongo');

// @desc        Delete order
// @route       DELETE /api/v1/orders/:id
// @access      Private
exports.deleteOrder = asyncHandler(async (req, res, next) => {
    let order = await Order.findById(req.params.id)

    if (!order) return next(
        res.status(404).json({ success: false, data: null })
    )

    await order.remove().then( items => {
        // Cascade delete -OrderItem-
        items.orderItems.forEach( el => OrderItem.findById(el).remove().exec())
    }).catch(e => { res.status(400).json({ success: false, data: e }) });

    res.status(201).json({ success: true, data: null });
});

https://mongoosejs.com/docs/api/model.html#model_Model-remove

btxsgosb

btxsgosb6#

与Mongoose核心一样,相关文档是用type:mongoose.Schema.Types.ObjectId和ref:'Related_Model'的组合指定的。此插件为ObjectID类型增加了两个配置选项:$through和$cascadeDelete。
$through定义了相关文档的路径,该路径是对该文档的引用。如果你有两个这样的schema:
var pagingRelations = require('paging-relations'); var fooSchema = new mongoose.Schema({ title:String,bars:[{ type:mongoose.Schema.Types.ObjectId,ref:'Bar ',$through:'foo' }] });
//应用插件fooSchema.plugin(fooingRelations);
var barSchema = new mongoose.Schema({ title:String,foo:{ type:mongoose.Schema.Types.ObjectId,ref:'Foo ' } });
//应用插件barSchema.plugin(pagingRelations);
如果在运行remove()后立即查询数据库,级联删除进程可能仍未完成。在我们的测试中,我们只需等待5秒钟,然后检查过程是否成功。

相关问题