Dovresti annidare le tue chiamate per rimuovere l'ID prodotto dall'altro modello. Ad esempio, nella tua chiamata per rimuovere il prodotto dal Product
raccolta, potresti anche effettuare un'altra chiamata per rimuovere il riferimento dal Partner
modello all'interno del callback dei risultati. La rimozione del prodotto per impostazione predefinita rimuoverà i suoi riferimenti alla Campaign
Modello.
Il codice seguente mostra l'intuizione di cui sopra:
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);
}
);
});
});
Per rimuovere le campagne associate, potrebbe essere necessaria un'operazione di rimozione aggiuntiva che acquisisca l'ID campagna associato da un determinato ID prodotto. Considera il seguente sporco trucco che potrebbe potenzialmente assegnarti un biglietto di sola andata per callback hell se non stai attento con l'annidamento della richiamata:
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);
})
}
);
}
);
});
Sebbene funzioni, la potenziale trappola di cui sopra può essere evitata utilizzando async/await o async
biblioteca. Ma in primo luogo, per darti una migliore comprensione dell'utilizzo di più callback con async
modulo, illustriamolo con un esempio tratto da Seven Cose che dovresti smettere di fare con Node.js
di più operazioni con callback per trovare un'entità padre, quindi trova le entità figlio che appartengono al genitore:
methodA(function(a){
methodB(function(b){
methodC(function(c){
methodD(function(d){
// Final callback code
})
})
})
})
Con async/await, le tue chiamate verranno ristrutturate strutturate come
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
}
})
Con il modulo async, puoi utilizzare il metodo series per affrontare l'uso di callback per il codice di annidamento di più metodi che possono risultare in Richiamata all'inferno :
Serie :
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
}
)
O la cascata :
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'
}
)
Ora tornando al tuo codice, usando il metodo a cascata asincrono potresti quindi ristrutturare il tuo codice in
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
});
});