2013-06-05 10 views
5

私は、ノード、エクスプレス、モンゴーを学んでいて、その過程で、JavaScriptです。私は、rssparserを使って物語のリストを取得し、それらをmongooseを使ってmongoデータベースに保存する機能を得ようとしています。配列を反復処理して、マングースに保存するのに問題があります。コールバックの問題?

私はRSSの取り込みを手に入れました。私はその話を繰り返しています。私は問題を抱えています。私は、1)ストーリーがデータベースにまだ存在していないことを確認し、2)そうでなければ保存する。私は、コールバックの処理方法が失われていると思います。ここに私の現在のコードとコメントがあります。

rssparser.parseURL(url, options, function(err,out){ 
    // out.items is an array of the items pulled 
    var items = out.items; 
    var story; 
    for (var i=0; i<items.length; i++){ 

     //create a mongoose story 
     story = new schemas.Stories({ 
      title: items[i].title, 
      url: items[i].url, 
      summary: items[i].summary, 
      published: items[i].published_at 
     }); 

     //TODO: for testing - these show up correctly. 
     //If I pull 10 stories, I get 10 entries from here that match 
     //So "story" is holding the current story 
     console.log("items[i] is :" + items[i].title); 
     console.log("story title is : " + story.title); 

     // setup query to see if it's already in db 
     var query = schemas.Stories.findOne({ 
      "title" : story.title, 
      "url" : story.url 
     }); 


     //execute the query 
     query.exec(function(err, row){ 
      if(err) console.log("error-query: " + err); 
      console.log("row: "+ row); 
      if(!row) { 
       // not there, so save 
       console.log('about to save story.title: ' + story.title); 
       story.save(function (err){ 
        console.log("error in save: " + err); 
       }); 
      } 
     }); 

    } 
}); 

これを実行すると、私が見ることはコンソール出力がたくさんある:

それはすべてのストーリー(多くは省略)を示す開始しています:

items[i] is :TSA Drops Plan to Let Passengers Carry Small Knives on Planes    
story title is : TSA Drops Plan to Let Passengers Carry Small Knives on Planes   
items[i] is :BUILDING COLLAPSE:1 Reportedly Dead, 13 Pulled From Philly Rubble   
story title is : BUILDING COLLAPSE:1 Reportedly Dead, 13 Pulled From Philly Rubble  
items[i] is :CONTROVERSIAL PAST: Obama's UN Nominee Once Likened US 'Sins' to Nazis'  
story title is : CONTROVERSIAL PAST: Obama's UN Nominee Once Likened US 'Sins' to Nazis' 
items[i] is :WRITING OUT WRIGHTS: Bill Gives First Powered Flight Nod to Whitehead  
story title is : WRITING OUT WRIGHTS: Bill Gives First Powered Flight Nod to Whitehead 
items[i] is :BREAKING NEWS: Rice Named to Top Security Post Despite Libya Fallout   
story title is : BREAKING NEWS: Rice Named to Top Security Post Despite Libya Fallout 

はその後(多くは省略)のように続けます。

row: null                  
about to save story.title: Best Ribs in America        
row: null                  
about to save story.title: Best Ribs in America        
row: null                  
about to save story.title: Best Ribs in America        
row: null                  
about to save story.title: Best Ribs in America        
row: null                  
about to save story.title: Best Ribs in America        
row: null                  
about to save story.title: Best Ribs in America        
row: { title: 'Best Ribs in America',           
    url: 'http://www.foxnews.com/leisure/2013/06/05/10-best-ribs-in-america/', 
    published: 1370463800000,             
    _id: 51af9f881995d40425000023,            
    __v: 0 }                  

「約保存する」タイトル(フィードの最後のストーリー)を繰り返します。最後の行が示すように、一度ストーリー。

console.logの出力には、すべてのストーリータイトルの出力が上に表示され、次にすべてのものが下のquery.exec()コールの内側から表示されます。すべてのヘルプは高く評価され

...

答えて

1

これに伴う問題は、EXECコールバックで参照物語は最後のものは、forループの中で繰り返されるものにセットされているということです、一度にコールバックが得られます実行された関数のすべてが同じ変数のインスタンスを参照しているためです。

これは単にあなたがのように、すぐにパラメータを持つ実行機能では、forループで各事をラップすることです解決する最も簡単な方法:私はこれをテストしていません

rssparser.parseURL(url, options, function(err,out){ 
    // out.items is an array of the items pulled 
    var items = out.items; 
    for (var i=0; i<items.length; i++){ 
     (function(item) { 

      //create a mongoose story 
      var story = new schemas.Stories({ 
       title: item.title, 
       url: item.url, 
       summary: item.summary, 
       published: item.published_at 
      }); 

      // setup query to see if it's already in db 
      var query = schemas.Stories.findOne({ 
       "title" : story.title, 
       "url" : story.url 
      }); 

      //execute the query 
      query.exec(function(err, row){ 
       if(err) console.log("error-query: " + err); 
       console.log("row: "+ row); 
       if(!row) { 
        // not there, so save 
        console.log('about to save story.title: ' + story.title); 
        story.save(function (err){ 
         console.log("error in save: " + err); 
        }); 
       } 
      }); 

     })(items[i]); 
    } 
}); 

が、私

あなたのプラットフォームでサポートされている場合は、配列のforEachループ内の項目を繰り返し処理する方が簡単でクリーンで、より良い方法です(どのnode.js ) - このバージョンはもっときれいです:

rssparser.parseURL(url, options, function(err,out){ 
    // out.items is an array of the items pulled 
    out.items.forEach(function(item) { 

     //create a mongoose story 
     var story = new schemas.Stories({ 
      title: item.title, 
      url: item.url, 
      summary: item.summary, 
      published: item.published_at 
     }); 

     // setup query to see if it's already in db 
     var query = schemas.Stories.findOne({ 
      "title" : story.title, 
      "url" : story.url 
     }); 

     //execute the query 
     query.exec(function(err, row){ 
      if(err) console.log("error-query: " + err); 
      console.log("row: "+ row); 
      if(!row) { 
       // not there, so save 
       console.log('about to save story.title: ' + story.title); 
       story.save(function (err){ 
        console.log("error in save: " + err); 
       }); 
      } 
     }); 

    }); 
}); 
+0

私はクリーナーメソッドを実装し、それは素晴らしい、ありがとう。私の問題はちょうどタイミング問題でしたか?つまり、out.items内のすべての項目が、そのコールバックが実行される前に反復されています(したがって、最後のout.itemに設定されたストーリー)。 – Mike

+0

問題はスコープと関連があり、結果として競合状態になりました。 forループが反復処理されるとき、 'story'への参照が1つだけあり、配列を反復処理するたびにオーバーライドされます。もしexec関数がすぐに実行されていたら、コードはうまくいきましたが、execのコールバックはすべてforループが終了した後に起こるので、変数に割り当てられたストーリーの最後のインスタンスを参照しますストーリー。彼らが関数で "閉じた"とき、彼らはすべて 'story'のインスタンスを持っています。これは非常に一般的な間違いです – arnorhs

2

よく、ノードはイベント駆動型サーバーで、javascriptもイベント駆動型であるため、スタッフを非同期に呼び出すことができます。

必要な処理を行うには、非同期パターンを使用する必要があります。あなたはそれがすでに再びデシベルを照会せずに存在している項目を確認するために、スキーマクラスの利用可能mongooseを使用している場合

まず、:

var mongoose = require('mongoose'); 

var schema = new mongoose.Schema({ 
    title: String, 
    url: { type: String, unique: true }, 
    summary: String, 
    published: Date 

}) 

var model = mongoose.model('stories', schema) 

URLがユニークなので、保存し、重複が発生しますエラーとmongooseはクエリを保存しません。

今、我々はそれのためのパターンのいくつかの種類を必要とする各1を項目を反復処理し、保存するために、幸いにも我々はそれのためにasyncを持っている:我々はないそうであるように、我々は並列モードで非同期を使用

var async = require('async'); 

rssparser.parseURL(url, options, function(err, out){ 
    async.each(out.items, function(item, callback){ 

     var m = new model({ 
      title: item.title, 
      url: item.url, 
      summary: item.summary, 
      published: item.published_at 
     }) 

     m.save(function(err, result){ 
      callback(null) 
     }); 

    }, function(err){ 
     //we complete the saving we can do stuff here  
    }); 
} 

重複しているかどうか注意してください。 配列を使ってそれを追跡することもできます。結果ので あなたはあなたが保存したアイテムの数を見ることができます。

+0

ねえ、ありがとう、それは目標を達成するためのよりよい方法かもしれません。とても有難い! – Mike

関連する問題