我正在尝试将多个标签保存到我刚刚创建的特定产品中。我成功地将标签推入了产品集合,但是当我尝试保存它时,我遇到了一个错误:无法多次并行保存()相同的文档。
我正在使用mongoDB,node和Mongoose。
这是我的模式
var tagSchema = mongoose.Schema({
tagname: String,
});
var tag = mongoose.model('Tag', tagSchema);
var Item = new Schema({
title : String,
description : String,
price : Number,
tags: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Tag"
}]
});
var product = mongoose.model('Product', Item);
这是我尝试在数据库中创建具有关联标签的新产品时来自node.js的代码(来自HTML表单)
product.create(req.body.product, function(err, newitem){
if(err){
console.log(err);
}else{
console.log(req.body.tags); // gives ["fun","cheap"] from the form
req.body.tags.forEach(function(newtag){
tag.findOne({tagname : newtag},function(err, finalcast){
newitem.tags.push(finalcast);
console.log(newitem); // gives the product with the tag collections in it.
});
newitem.save(); // error Can't save() the same doc multiple times in parallel.
console.log(newitem); // the product collection has an empty tags[]
});
res.redirect("/");
}
});
如何一次将标签集合直接保存在产品中?最好先创建产品,然后使用push逐个插入标签?
非常感谢您的帮助!
答案 0 :(得分:1)
问题可能是因为您试图通过推入对象而不是_id
newitem.tags.push(finalcast);
尝试像这样推送对象的_id:
newitem.tags.push(finalcast._id);
答案 1 :(得分:0)
我认为这与Asynchrone JS有关,但我不确定。循环似乎不是一个好主意...
如何轻松地将多个标签文档保存到一个产品文档中?
答案 2 :(得分:0)
好几个小时后,我找到了解决方案。我真的不知道这是否是一个好方法,但是它有效。我在forEach中插入一个if(),仅在完成forEach循环时保存:
req.body.tags.forEach(function(newtag, index){
tag.findOne({tagname : newtag},function(err, finalcast){
newitem.tags.push(finalcast);
if(index + 1 == req.body.tags.length){
newitem.save();
res.redirect("/");
}
});
答案 3 :(得分:0)
您正在forEach
循环中一次执行所有操作,这使得很难知道何时完成数据库操作。这也意味着您正在实际完成操作之前触发res.redirect
。我会为此使用异步/等待。我写得很快,还没有测试,但我认为它应该可以工作:
const tagSchema = mongoose.Schema({
tagname: String
})
const Tag = mongoose.model('Tag', tagSchema)
const itemSchema = new Schema({
title: String,
description: String,
price: Number,
tags: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Tag"
}]
})
const Product = mongoose.model('Product', itemSchema)
const createProduct = async (req, res) => {
const { tags, product } = req.body
try {
const product = new Product(product)
for (let i = 0; i < tags.length; i++) {
const tagName = tags[i]
const existingTag = await Tag.findOne({ tagname: tagName })
if (!existingTag) {
await new Tag({ tagname: tagName}).save()
}
}
await product.save()
res.redirect('/')
} catch (error) {
console.log(error)
}
}
在代码中,我做了几件事: