简体   繁体   English

无法迭代数组并保存到mongoose。 回调问题?

[英]Having trouble iterating through array and saving to mongoose. Callback issue?

I'm learning node, express, mongo, and, in the process, javascript. 我正在学习节点,表达,mongo,以及在此过程中,javascript。 I'm trying to get a feature where using rssparser, get a list of stories and save them to a mongo database with mongoose. 我正在尝试使用rssparser获取一个功能,获取故事列表并将其保存到mongoose的mongo数据库中。

I've got the RSS pull working, and I'm iterating through the stories, it's the saving that I'm having problems with. 我已经完成了RSS工作,而且我正在重复这些故事,这是我遇到问题的拯救。 I want to 1) check that the story doesn't already exist in the database, and 2) if not, save it. 我想1)检查数据库中是否存在故事,2)如果没有,请保存。 I think I'm getting lost in the way callbacks are handled. 我想我在处理回调的过程中迷失了方向。 Here's my current code, with comments. 这是我当前的代码,带有注释。

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

    }
});

When this runs, what I see is alot of console output: 当这个运行时,我看到的是很多控制台输出:

It's starts showing all the stories (many omitted): 它开始显示所有故事(许多省略):

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   

Then continues like (many omitted): 然后继续像(许多省略):

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 }                                                                    

It repeats the "about to save" title (which is the last story in the feed), and it saves the story once, like the last row shows. 它重复了“即将保存”标题(这是Feed中的最后一个故事),并且它保存了一次故事,就像最后一行所示。

The console.log output shows just I put it, all the story title output at the top, then all the stuff from inside the query.exec() call at the bottom. console.log输出显示我把它,所有的故事标题输出在顶部,然后从底部的query.exec()调用内的所有东西。

Any help is appreciated... 任何帮助表示赞赏......

The problem with this is that the story referenced in the exec callback will have been set to whatever is the last thing iterated on in the for loop, once the callback will get executed, since all of the executed functions are referencing the same instance of the variable. 这个问题是exec回调中引用的故事将被设置为for循环中迭代的最后一件事,一旦回调将被执行,因为所有执行的函数都引用了相同的实例。变量。

The easiest way to fix this is to simply wrap each thing in the for loop in a function that you execute right away with parameters, as in: 解决这个问题的最简单方法是简单地将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]);
    }
});

I haven't tested this, but I'm sure you'll find that it will fix your issue 我没有测试过这个,但我相信你会发现它会解决你的问题

Another even easier, cleaner, better way would be to iterate over the items in a forEach loop on the array, if your platform supports that (which node.js does) - this version is even more prettier: 另一个更简单,更简洁,更好的方法是迭代数组上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);
                });
            }
        });

    });
});

well, node is event driven server and javascript is also event driven, so you can call stuff asynchronously. 好吧,节点是事件驱动的服务器,javascript也是事件驱动的,所以你可以异步调用东西。

you need to use some async patterns to do what you want. 你需要使用一些异步模式来做你想要的。

first, if you are using mongoose you can utilize it's schema class to check for items that are already exists without querying the db again: 首先,如果您使用的是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)

the url is unique, so the save will cause a duplicate error and mongoose won't save the query. url是唯一的,因此保存将导致重复错误,并且mongoose将不保存查询。

now to iterate through the items and save each one we need some kind of a pattern for it, luckily we have async for it: 现在迭代这些项目并保存每个项目,我们需要某种模式,幸运的是我们有异步

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

we used async in a parallel mode as we don't care if some are duplicate or not. 我们在并行模式下使用async,因为我们不关心某些是否重复。 you can also track it with an array that you can push to it the err || 你也可以用一个数组跟踪它,你可以推送它错误的|| result so you can see how many items you saved. 结果,这样您就可以看到保存了多少项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM