他のモデルから製品IDを削除するには、呼び出しをネストする必要があります。たとえば、 Product
から製品を削除するための呼び出しで コレクションの場合は、別の呼び出しを行って Partner
から参照を削除することもできます。 結果コールバック内のモデル。デフォルトで製品を削除すると、キャンペーン
への参照が削除されます モデル。
次のコードは、上記の直感を示しています。
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を取得する追加の削除操作が必要になる場合があります。 コールバック地獄 への片道チケットを獲得する可能性のある次の汚いハックを考えてみてください。 コールバックのネストに注意しない場合:
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で複数のコールバックを使用する方法をよりよく理解するためにコード>
モジュール、Sevenの例でこれを説明しましょうNode.jsでやめるべきこと
親エンティティを検索し、次に親に属する子エンティティを検索するためのコールバックを使用した複数の操作の例:
methodA(function(a){
methodB(function(b){
methodC(function(c){
methodD(function(d){
// Final callback code
})
})
})
})
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
}
})
asyncモジュールを使用すると、seriesメソッドを使用して、複数のメソッドのコードをネストするためのコールバックの使用に対処できます。これにより、 コールバック地獄 :
シリーズ :
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'
}
)
ここでコードに戻り、非同期ウォーターフォールメソッドを使用して、コードを次のように再構築できます
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
});
});