Node.js MongoDB mongoose子文档创建两次

Node.js MongoDB mongoose子文档创建两次,node.js,mongodb,express,mongoose,mean-stack,Node.js,Mongodb,Express,Mongoose,Mean Stack,我使用一个简单的表格,可以用来注册一个网站的文章 后端如下所示: // Post new article app.post("/articles", function(req, res){ var newArticle = {}; newArticle.title = req.body.title; newArticle.description = req.body.description; var date = req

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

后端如下所示:

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

      }


  });

});
平台字段作为字符串数组传递到后端,一个字符串表示一个objectID。当平台仅包含1个字符串(即1个要链接的平台)时,一切正常。当平台包含多个字符串时。创建的文章具有每个平台的副本。或者有时只是一些平台的副本

有什么想法吗

更新1: 文章模式: var mongoose=要求(“mongoose”)

平台架构:

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

移动保存功能

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

尝试中的forEach循环无法在下一次迭代之前识别
findById()
异步方法的回调完成。您需要使用任何库方法
async.each
async.while
、或
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.each()
实用程序函数迭代平台列表,对每个id执行异步任务,使用更新平台,完成后将对象变量中的更新查询结果返回给下一个函数

最后一个函数将使用以前管道中的平台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);
});

您能否提出问题,向我们展示
文章
平台
模型的模式定义?我可以看到您正在循环中进行异步调用,这可能解释了为什么您会得到重复的。更新@圣诞手帕很多。2个简短的问题。我是否必须对另一个保存功能执行相同的操作。这里出了什么问题是这样的,因为在循环中使用了异步函数。请参见editSo我应该用这个替换我的其他内容?如果你正在编辑链接到文章@chridamCan的平台,你会如何应用这个?请为此创建一个新问题?我想知道你是否介意查看我发布的关于同一问题的新问题@白蚁
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);
});