2016-11-02 18 views
1

私はウェブサイトに記事を登録するために使用できるシンプルなフォームを使用しています。MongoDB mongooseサブ文書を2回作成

バックエンドは、次のようになります。

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

     } 


    }); 

}); 

プラットフォームフィールドは、文字列の配列、1オブジェクトIDである1つの文字列としてバックエンドに渡されます。プラットフォームに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.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()ユーティリティ関数を使用していますfindByIdAndUpdate()を使用してプラットフォームを更新するために、各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); 
}); 
+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()); 
     } 
    }); 
} 

を保存EDIT

その移動を

article.saveを呼び出すのは1回だけで、各ループでは呼び出されません。さらに、同期関数として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

を参照してください。だから、私は他のすべてのものをこれで置き換えるべきですか? –

関連する問題