考虑到 Mongoose Node.js 中的引用,如何删除对象?
How to remove object taking into account references in 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
中的引用 ID 以及属于此 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
中删除产品的电话中
集合,您还可以进行另一个调用以从结果回调中的 Partner
模型中删除引用。默认情况下删除产品将删除其对 Campaign
模型的引用。
下面的代码展示了上面的直觉:
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,如果不注意回调嵌套,它可能会奖励你一张 one-way 到 callback hell 的票:
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
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 多个带有回调的操作来查找 parent 实体,从而避免上述潜在陷阱,然后找到属于 parent:
的 child 个实体
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 方法来解决使用回调来嵌套多个方法的代码,这可能会导致 Callback Hell:
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
}
)
或者 waterfall:
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
});
});
这是我的 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
中的引用 ID 以及属于此 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
中删除产品的电话中
集合,您还可以进行另一个调用以从结果回调中的 Partner
模型中删除引用。默认情况下删除产品将删除其对 Campaign
模型的引用。
下面的代码展示了上面的直觉:
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,如果不注意回调嵌套,它可能会奖励你一张 one-way 到 callback hell 的票:
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
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 多个带有回调的操作来查找 parent 实体,从而避免上述潜在陷阱,然后找到属于 parent:
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 方法来解决使用回调来嵌套多个方法的代码,这可能会导致 Callback Hell:
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
}
)
或者 waterfall:
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
});
});