MongoDB mongoose子文档创建两次
我正在使用可用于将文章注册到网站的简单表单。
后端看起来像这样:
// Post new article
app.post("/articles", function(req, res){
var newArticle = {};
newArticle.title = req.body.title;
newArticle.description = req.body.description;
var date = req.body.date;
var split = date.split("/");
newArticle.date = split[1]+'/'+split[0]+'/'+split[2];
newArticle.link = req.body.link;
newArticle.body = req.body.body;
var platforms = req.body.platforms;
console.log(platforms);
Article.create(newArticle, function(err, createdArticle){
if(err){
console.log(err.message);
} else {
var counter=0;
platforms.forEach(function(platform){
var platformed=mongoose.mongo.ObjectID(platform);
Platform.findById(platformed, function(err, foundPlatform){
if(err){
console.log(err);
} else {
counter++;
foundPlatform.articles.push(createdArticle);
foundPlatform.save();
createdArticle.platforms.push(foundPlatform);
createdArticle.save();
if(counter==platforms.length){
res.redirect('articles/' + createdArticle._id);
}
}
});
});
}
});
});
平台字段作为字符串数组传递到后端,一个字符串是一个对象ID。 当平台只包含1个字符串,即1个要链接的平台时,一切正常。 当平台包含多个字符串时。 创建的文章有每个平台的重复。 或者有时候只是某些平台的重复
有任何想法吗?
更新1:文章模式:var mongoose = require(“mongoose”);
var articleSchema = new mongoose.Schema({
title : String,
description : String,
link : String,
date : String,
body : String,
platforms : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Platform"
}
]
})
module.exports = mongoose.model("Article", articleSchema);
平台架构:
var mongoose = require("mongoose");
var platformSchema = new mongoose.Schema({
name : String,
category : String,
contacts : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Contact"
}
],
website : String,
country : String,
contactInformation : String,
businessModelNotes : String,
source : String,
generalNotes : String,
projects : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Project"
}
],
articles : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Article"
}
],
privacy : String,
comments : [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
module.exports = mongoose.model("Platform", platformSchema);
您尝试的forEach循环在下一次迭代之前无法识别findById()
异步方法的回调完成。 您需要使用任何async.each
, async.whilst
或async.until
等效于for循环的任何async
库方法,并且在继续执行下一次迭代之前将等待异步的回调(换句话说, for循环会产生)。
例如:
var platform_docs = [];
async.each(platforms, function(id, callback) {
Platform.findById(id, function(err, platform) {
if (platform)
platform_docs.push(platform);
callback(err);
});
}, function(err) {
// code to run on completion or err
console.log(platform_docs);
});
对于整个操作,可以使用async.waterfall()
方法,它允许每个函数将其结果传递到下一个函数。
该方法中的第一个函数创建新文章。
第二个函数使用async.each()
实用程序函数遍历平台列表,为每个id执行一个异步任务以使用findByIdAndUpdate()
更新平台,并在完成时返回更新查询的结果一个对象变量到下一个函数。
最终的函数将使用上一个管道中的平台ID更新新创建的文章。
类似下面的例子:
var newArticle = {},
platforms = req.body.platforms,
date = req.body.date,
split = date.split("/");
newArticle.title = req.body.title;
newArticle.description = req.body.description;
newArticle.date = split[2]+'/'+split[0]+'/'+split[2];
newArticle.link = req.body.link;
newArticle.body = req.body.body;
console.log(platforms);
async.waterfall([
// Create the article
function(callback) {
var article = new Article(newArticle);
article.save(function(err, article){
if (err) return callback(err);
callback(null, article);
});
},
// Query and update the platforms
function(articleData, callback) {
var platform_ids = [];
async.each(platforms, function(id, callback) {
Platform.findByIdAndUpdate(id,
{ "$push": { "articles": articleData._id } },
{ "new": true },
function(err, platform) {
if (platform)
platform_ids.push(platform._id);
callback(err);
}
);
}, function(err) {
// code to run on completion or err
if (err) return callback(err);
console.log(platform_ids);
callback(null, {
"article": articleData,
"platform_ids": platform_ids
});
});
},
// Update the article
function(obj, callback) {
var article = obj.article;
obj.platform_ids.forEach(function(id){ article.platforms.push(id); });
article.save(function(err, article){
if (err) return callback(err);
callback(null, article);
});
}
], function(err, result) {
/*
This function gets called after the above tasks
have called their "task callbacks"
*/
if (err) return next(err);
console.log(result);
res.redirect('articles/' + result._id);
});
移动你的保存功能
if(counter==platforms.length){
createdArticle.save(function(err, savedObject){
if(err || !savedObject) console.log(err || "not saved");
else {
res.redirect('articles/' + savedObject._id.toString());
}
});
}
=============编辑
因为你只需要调用article.save一次,而不是每个循环。 此外,您使用save()作为同步功能,但它是异步的。
我认为你应该使用直接更新功能:
} else {
var counter=0;
// map plateform array id with ObjectID
var idarray = platforms.map(function(e){return mongoose.mongo.ObjectID(e);});
// update all plateform with article id
Platform.update({_id:{$in: idarray}}, {$push:{articles: createdArticle}}, {multi:true, upsert:false}, function(err, raw){
if(err)
{
// error case
return res.status(403).json({});
}
// retrieve plateform
Platform.find({_id:{$in: idarray}}, function(err, results){
if(err || !results)
{
// error case
return res.status(403).json({});
}
Article.update({_id: createdArticle._id.toString()}, {$push:{platforms:{$each: results}}}, {multi:false, upsert:false}, function(err, saved){
if(err || !saved)
{
// error
return res.status(403).json({});
}
res.redirect('articles/' + savedObject._id.toString());
});
});
});
但是,存储完整的对象是个坏主意,为什么不只存储id?
链接地址: http://www.djcxy.com/p/60695.html上一篇: MongoDB mongoose subdocuments created twice
下一篇: Mongoose Schema with nested optional object with required fields