且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

考虑到 Mongoose Node.js 中的引用,如何删除对象?

更新时间:2023-01-22 12:19:33

您必须嵌套调用以从其他模型中删除产品 ID.例如,在您从 Product 中删除产品的调用中集合,您还可以再次调用以从结果回调中的 Partner 模型中删除 ref.默认情况下删除产品将删除其对 Campaign 模型的引用.

You would have to nest your calls to remove the product id from the other model. For instance, in your call to remove the product from the Product collection, you could also make another call to remove the ref from the Partner model within the results callback. Removing the product by default will remove its refs to the Campaign Model.

以下代码显示了上面的直觉:

The following code shows the intuition above:

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);
            }
        );
    });
});

要删除关联的广告系列,您可能需要一个额外的删除操作,该操作从给定的产品 ID 中获取相关的广告系列 ID.考虑以下肮脏的 hack,如果不小心回调嵌套,它可能会给你一张单程票到 回调地狱:

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);
                                })
                }
            );
        }
    );
});

虽然它有效,但通过使用 async/await 或 async 库.但首先,为了让您更好地理解通过 async使用多个回调> 模块,让我们用 你应该停止使用 Node.js 做的七件事 使用回调的多个操作找到父实体,然后找到属于父实体的子实体:


Although it works, the above potential pitfall can be avoided by using async/await or the async library. But firstly, to give you a better understanding of the using multiple callbacks with the async module, let's illustrate this with an example from Seven Things You Should Stop Doing with Node.js of multiple operations with callbacks to find a parent entity, then find child entities that belong to the parent:

methodA(function(a){
    methodB(function(b){
        methodC(function(c){
            methodD(function(d){
                // Final callback code        
            })
        })
    })
})

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

With async/await, your calls will be restructured structured as

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
    }
})

使用 async 模块,您可以使用系列方法来解决使用回调来嵌套多个方法的代码的问题,这可能会导致 回调地狱:

系列:

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
    }
)

或者瀑布:

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'    
    }
)

现在回到你的代码,使用异步瀑布方法,你可以重构你的代码


Now going back to your code, using the async waterfall method you could then restructure your code to

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
    });
});