2016-11-02 59 views
1

我正在使用一個簡單的表單,可用於將文章註冊到網站。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); 
         } 
        } 
       }); 
      }); 

     } 


    }); 

}); 

的平臺字段被傳遞到後端爲一個字符串數組,一個字符爲一個的objectID。當平臺只包含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); 
+0

你能[編輯]你的問題向我們展示了'Article'和'Platform'模型架構定義是什麼?我可以看到你在一個循環內進行異步調用,這可能解釋你爲什麼會得到重複。更新了 – chridam

+0

! @chridam –

回答

1

您嘗試的forEach循環無法識別在下一次迭代之前的異步方法的回調完成findById()異步方法。您需要使用async庫方法async.eachasync.whilstasync.until(它們與for循環相當)中的任意一個,並且在繼續進行下一次迭代(換句話說,將會產生的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); 
}); 
+0

如果您正在編輯與文章鏈接的平臺,您將如何應用此文檔@chridam –

+1

您能否爲此創建一個新問題? – chridam

+0

我想知道你是否會介意看看我發佈的關於這個問題的新問題。 [question2](http://stackoverflow.com/questions/42139856/editing-subdocments-n-n-relationship-in-mongodb)@chridam –

1

移動你的保存功能

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?

+0

非常感謝。 2個快速問題。我必須爲其他保存功能做同樣的事情嗎?這裏出了什麼問題 –

+0

是的,這是因爲你在循環中使用異步函數。請參閱編輯 – Dafuck

+0

因此,我應該用我的其他東西替換一切嗎? –

相關問題