如何在考虑Mongoose Node.js中的引用的情况下删除对象?

DiP*_*Pix 1 mongoose mongodb node.js mongoose-populate

这是我的MongoDB模式:

var partnerSchema = new mongoose.Schema({
    name: String,
    products: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Product'
        }]
});

var productSchema = new mongoose.Schema({
    name: String,
    campaign: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Campaign'
        }
    ]
});

var campaignSchema = new mongoose.Schema({
    name: String,
});


module.exports = {
    Partner: mongoose.model('Partner', partnerSchema),
    Product: mongoose.model('Product', productSchema),
    Campaign: mongoose.model('Campaign', campaignSchema)
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何在考虑引用的情况下从任何文档中删除对象(也许我应该以某种方式使用猫鼬填充)?例如,如果我要删除,Product那么我假设我还将也删除ref ID Partner和所有Campaigns属于this的引用ID Product

目前,我以这种方式删除:

var campSchema = require('../model/camp-schema');

    router.post('/removeProduct', function (req, res) {
            campSchema.Product.findOneAndRemove({ _id: req.body.productId }, function (err, response) {
                if (err) throw err;
                res.json(response);
            });
        });
Run Code Online (Sandbox Code Playgroud)

但是在mongo中仍然保留了引用。

chr*_*dam 5

您必须嵌套调用才能从其他模型中删除产品ID。例如,在您从Product 集合中删除产品的调用中,您还可以Partner在结果回调中进行另一个调用以从模型中删除引用。默认情况下删除产品将删除其对Campaign模型的引用。

以下代码显示了上述直觉:

var campSchema = require('../model/camp-schema');

router.post('/removeProduct', function (req, res) {
    campSchema.Product.findOneAndRemove({ _id: req.body.productId }, function (err, response) {
        if (err) throw err;
        campSchema.Partner.update(
            { "products": req.body.productId },
            { "$pull": { "products": req.body.productId } },
            function (err, res){
                if (err) throw err;
                res.json(res);
            }
        );
    });
});
Run Code Online (Sandbox Code Playgroud)

要删除关联的广告系列,您可能需要执行额外的删除操作,该操作需要从给定的产品ID中获取关联的广告系列ID。考虑以下肮脏的技巧,如果不仔细考虑回调嵌套,可能会授予您单程回调地狱的票:

router.post('/removeProduct', function (req, res) {
    campSchema.Product.findOneAndRemove(
        { _id: req.body.productId }, 
        { new: true },
        function (err, product) {
            if (err) throw err;
            campSchema.Partner.update(
                { "products": req.body.productId },
                { "$pull": { "products": req.body.productId } },
                function (err, res){
                    if (err) throw err;
                    var campaignList = product.campaign
                    campSchema.Campaign.remove({ "_id": { "$in": campaignList } })
                                .exec(function (err, res){
                                    if (err) throw err;
                                    res.json(product);
                                })
                }
            );
        }
    );
});
Run Code Online (Sandbox Code Playgroud)

尽管可行,但可以通过使用async / await或async库来避免上述潜在的陷阱。但是首先,为了让您更好地了解如何在async模块中使用多个回调,让我们以“ 您应该停止对Node.js进行的七件事”中的示例为例进行说明,该操作涉及多个回调,以查找父实体,然后找到子实体属于父母的:

methodA(function(a){
    methodB(function(b){
        methodC(function(c){
            methodD(function(d){
                // Final callback code        
            })
        })
    })
})
Run Code Online (Sandbox Code Playgroud)

使用async / await,您的呼叫将被重组为

router.post('/removeProduct', async (req, res) => {
    try {
        const product = await campSchema.Product.findOneAndRemove(
            { _id: req.body.productId }, 
            { new: true }
        )

        await campSchema.Partner.update(
            { "products": req.body.productId },
            { "$pull": { "products": req.body.productId } }
        )

        await campSchema.Campaign.remove({ "_id": { "$in": product.campaign } })

        res.json(product)
    } catch(err) {
        throw err
    }
})
Run Code Online (Sandbox Code Playgroud)

使用异步模块,您可以使用series方法来解决将回调方法用于嵌套多个方法的代码的问题,这可能会导致Callback Hell

系列

async.series([
    function(callback){
        // code a
        callback(null, 'a')
    },
    function(callback){
        // code b
        callback(null, 'b')
    },
    function(callback){
        // code c
        callback(null, 'c')
    },
    function(callback){
        // code d
        callback(null, 'd')
    }],
    // optional callback
    function(err, results){
        // results is ['a', 'b', 'c', 'd']
        // final callback code
    }
)
Run Code Online (Sandbox Code Playgroud)

瀑布

async.waterfall([
    function(callback){
        // code a
        callback(null, 'a', 'b')
    },
    function(arg1, arg2, callback){
        // arg1 is equals 'a' and arg2 is 'b'
        // Code c
        callback(null, 'c')
    },
    function(arg1, callback){      
        // arg1 is 'c'
        // code d
        callback(null, 'd');
    }], function (err, result) {
        // result is 'd'    
    }
)
Run Code Online (Sandbox Code Playgroud)

现在回到代码,使用异步瀑布方法,然后可以将代码重构为

router.post('/removeProduct', function (req, res) {
    async.waterfall([
        function (callback) {
            // code a: Remove Product
            campSchema.Product.findOneAndRemove(
                { _id: req.body.productId }, 
                function (err, product) {
                    if (err) callback(err);
                    callback(null, product);
                }
            );
        },

        function (doc, callback) {
            // code b: Remove associated campaigns
            var campaignList = doc.campaign;
            campSchema.Campaign
                .remove({ "_id": { "$in": campaignList } })
                .exec(function (err, res) {
                if (err) callback(err);
                callback(null, doc);
            }
            );
        },

        function (doc, callback) {
            // code c: Remove related partner
            campSchema.Partner.update(
                { "products": doc._id },
                { "$pull": { "products": doc._id } },
                function (err, res) {
                    if (err) callback(err);
                    callback(null, doc);
                }
            );
        }
    ], function (err, result) {
        if (err) throw err;
        res.json(result);  // OUTPUT OK
    });
});
Run Code Online (Sandbox Code Playgroud)