MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Wie entferne ich Objekte unter Berücksichtigung von Referenzen in Mongoose Node.js?

Sie müssten Ihre Aufrufe verschachteln, um die Produkt-ID aus dem anderen Modell zu entfernen. Zum Beispiel in Ihrem Aufruf, das Produkt aus Product zu entfernen Sammlung, könnten Sie auch einen weiteren Aufruf tätigen, um die Referenz aus dem Partner zu entfernen model innerhalb des Ergebnis-Callbacks. Wenn Sie das Produkt standardmäßig entfernen, werden seine Verweise auf die Campaign entfernt Modell.

Der folgende Code zeigt die obige Intuition:

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

Um die zugehörigen Kampagnen zu entfernen, benötigen Sie möglicherweise einen zusätzlichen Entfernungsvorgang, der die zugehörige Kampagnen-ID für eine bestimmte Produkt-ID übernimmt. Betrachten Sie den folgenden schmutzigen Hack, der Ihnen möglicherweise ein One-Way-Ticket in die Callback-Hölle einbringt wenn man nicht aufpasst mit der Callback-Verschachtelung:

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

Obwohl es funktioniert, kann der obige potenzielle Fallstrick vermieden werden, indem async/await oder async Bibliothek. Aber zuerst, um Ihnen ein besseres Verständnis für die Verwendung mehrerer Rückrufe mit dem async veranschaulichen wir dies anhand eines Beispiels aus Seven Dinge, die Sie mit Node.js nicht mehr tun sollten von mehreren Operationen mit Rückrufen, um eine übergeordnete Entität zu finden, und dann untergeordnete Entitäten zu finden, die der übergeordneten gehören:

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

Mit async/await werden Ihre Aufrufe als

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

Mit dem async-Modul können Sie entweder die series-Methode verwenden, um die Verwendung von Rückrufen zum Verschachteln von Code mehrerer Methoden zu adressieren, was zu Callback Hell :

Reihe :

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

Oder der Wasserfall :

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

Kehren Sie nun zu Ihrem Code zurück und verwenden Sie die asynchrone Wasserfallmethode, mit der Sie Ihren Code dann umstrukturieren könnten

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