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

这是我的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) } 

我想知道如何从任何文档中删除对象考虑到引用(也许我应该用某种方式从mongoose填充)? 例如,如果我将删除Product那么我认为我将删除Partner参考编号以及属于此Product所有Campaigns

目前我以这种方式移除:

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

不过在mongo中仍然有引用。

您将不得不嵌套您的呼叫从其他模型中删除产品ID。 例如,在您从Product集合中删除产品的调用中,也可以再次调用结果callback中的Partner模型中的ref。 默认情况下删除产品会将其参考文件移除到Campaign Model。

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

 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中。 考虑以下肮脏的黑客可能会奖励你一个单向票callback地狱,如果不小心的callback嵌套:

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

尽pipe它起作用,但通过使用async库可以避免上述潜在的缺陷。 但首先,为了让您更好地了解使用async模块的多重callback,下面以一个例子来说明这个问题: 您应该停止使用Node.js处理多个操作的callback以查找父实体,然后find孩子属于父级的实体:

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

使用asynchronous模块,您可以使用串联方法来解决多个方法的嵌套代码的callback的使用,这可能导致callback地狱

系列

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

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

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