MongoDB mongoose子文档创build两次

我正在使用一个简单的表单,可以用来注册一个网站的文章。

后端看起来像这样:

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

平台字段作为一个string数组传递到后端,一个string是一个objectID。 当平台只包含1个string,即1个平台要连接,一切工作正常。 当平台包含多个string时。 创build的文章有每个平台的重复。 或者有时只是某些平台的重复

有任何想法吗?

更新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()asynchronous方法的callback完成。 您需要使用任何async库方法async.eachasync.whilstasync.until它们相当于for循环),并且将等到async的callback被调用后再继续下一次迭代(换句话说, 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()方法,它允许每个函数将其结果传递给下一个函数。

方法中的第一个函数创build新的文章。

第二个函数使用async.each()实用程序函数遍历平台列表,为每个id执行一个asynchronous任务以使用findByIdAndUpdate()更新平台,并在完成时返回更新查询的结果一个对象variables到下一个函数。

最后一个函数将使用上一个pipe道中的平台ID更新新创build的文章。

像下面的例子:

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

移动你的保存function

 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()作为同步函数,但是它是asynchronous的。

我认为你应该使用直接更新function:

 } 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?