5

私はnode、express、mongo、そしてその過程で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 }                                                                    

「保存しようとしている」というタイトル (フィードの最後の記事) を繰り返し、最後の行が示すように、記事を 1 回保存します。

console.log の出力には、すべてのストーリー タイトルの出力が一番上に表示され、query.exec() 呼び出し内のすべてが一番下に表示されます。

どんな助けでも大歓迎です...

4

2 に答える 2

2

これに関する問題は、コールバックが実行されると、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]);
    }
});

これをテストしていませんが、問題が解決することがわかると確信しています

プラットフォームがそれをサポートしている場合 (node.js がサポートしている場合)、配列の forEach ループ内の項目を反復処理することも、さらに簡単でクリーンで優れた方法です。このバージョンはさらにきれいです。

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

    });
});
于 2013-06-06T09:54:25.063 に答える
2

ノードはイベント駆動型サーバーであり、javascript もイベント駆動型であるため、非同期で呼び出すことができます。

必要なことを行うには、いくつかの非同期パターンを使用する必要があります。

まず、mongooseを使用している場合は、そのスキーマ クラスを利用して、db に再度クエリを実行することなく、既に存在するアイテムを確認できます。

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 はクエリを保存しません。

アイテムを反復処理して各アイテムを保存するには、何らかのパターンが必要ですが、幸いなことに非同期があります。

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

一部が重複しているかどうかは気にしないため、並列モードで async を使用しました。err || にプッシュできる配列で追跡することもできます。結果を表示して、保存したアイテムの数を確認できます。

于 2013-06-09T22:03:10.527 に答える