使用Mongoose FindOne& amp;在循环中构建数组蓝鸟承诺

时间:2015-11-13 18:20:04

标签: node.js mongoose promise bluebird

我正在使用Node,Mongoose和Bluebird,并且正在开发一个提供多个RSS源的网站。

当检索到Feed时,我想从表中提取已保存到表格中的任何文章,并将它们与Feed中的任何新文章合并到一个数组中。我似乎无法找到方法在返回我的数组之前等待所有解析的promise。基本问题是,当loadRSSFeed被调用时,它基本上会立即调用返回articleList行。如何排列所有这些内容,以便在我的所有承诺全部解决之前不会返回任何内容?

这第一个功能只是包装了一切:

function loadRSSFeed(rss, newsSource) {
var articleList = [];

// Promise.each(rss.channel[0].item, function (article) {
rss.channel[0].item.forEach(function (article) {
    var item = {};
    item.link = tryEval(article, "article.link[0]");

    Promise(function() {
        return getArticle(newsSource, article, item, articleList)
        .then(function() {
             return articleList; 
        })
    })
})                 
};          

getArticle函数如下所示:

function getArticle(newsSource, article, item, articleList) {
return Articles.findOne({ link: article.link }, function (err, doc) {
    if (doc) {
        articleList.push(doc._doc);
    }
    else {
        item.title = tryEval(article, "article.title[0]");
        item.pubDate = tryEval(article, "article.pubDate[0]");
        item.sourceId = newsSource.id;
        item.sourceName = newsSource.name;

        if (item.pubDate) {
            try {
                item.pubDate = new Date(item.pubDate);
            }
            catch (err) {
                item.pubDate = "";
            }
        };

        item.contentSnippet = tryEval(article, "article.description[0]");
        if (item.contentSnippet.indexOf("<") > 0) {
            item.contentSnippet = item.contentSnippet.substring(0, item.contentSnippet.indexOf("<") - 1);
        };

        item.image = tryEval(article, "article['media:content'][0].$.url|article.thumbnail[0]");
        if (!item.image) {
            item.image = photoHunt(item);
            if (item.image) {
                item.contentSnippet = "";
            }
        };
        if (item.title && item.link && (item.image || item.contentSnippet)) {
            articleList.push(saveArticle(item));
        }
    }
})
} 

并且saveArticle函数如下所示:

function saveArticle(article) {
var curArticle = {};

if (article._id) {
    curArticle = article;
    curArticle._id = article._id;
    curArticle.isNew = false;
}
else {
    curArticle = new Articles();
    curArticle.title = article.title;
    curArticle.link = article.link;
    curArticle.pubDate = article.pubDate;
    curArticle.image = article.image;
    curArticle.contentSnippet = article.contentSnippet;
    curArticle.sourceName = article.name;
    curArticle.sourceId = article.sourceId;

    if (article.haters) {
        curArticle.haters = article.haters;
    };

    if (article.lovers) {
        curArticle.lovers = article.lovers;
    };

    if (article.readers) {
        curArticle.readers = article.readers;
    };
}
curArticle.save(function (err) {
    if (err)
        console.log(err);
});
return curArticle;
};

这就是文章模型的样子,以防这里出现问题:

var mongoose     = require('mongoose'), 
Schema       = mongoose.Schema;
// NewsSchema = new Schema({ name: String });   

var ArticlesSchema   = new Schema({
title: String,
link: String,
pubDate: Date,
image: String,
contentSnippet: String,
sourceName: String,
lovers: [],
haters: [],
readers: [],
forumLinks: []
});

module.exports = mongoose.model('Articles', ArticlesSchema);

1 个答案:

答案 0 :(得分:2)

在我看来,您可以使用Bluebird的Promise.map()来迭代所有RSS提要并等待所有这些提要完成:

function loadRSSFeed(rss, newsSource) {
    // Promise.each(rss.channel[0].item, function (article) {
    return Promise.map(rss.channel[0].item, function(article) {
        var item = {};
        item.link = tryEval(article, "article.link[0]");
        return getArticle(newsSource, article, item, articleList);
    }).then(function(articleList) {
        // filter out any empty items
        return articleList.filter(function(article) {
            return !!article;
        });
    });
}


function getArticle(newsSource, article, item) {
    var find = Promise.promisify(Articles.findOne, {context: Articles});
    return find({link: article.link}).then(doc) {
        if (doc) {
            return doc._doc;
        } else {
            item.title = tryEval(article, "article.title[0]");
            item.pubDate = tryEval(article, "article.pubDate[0]");
            item.sourceId = newsSource.id;
            item.sourceName = newsSource.name;
            if (item.pubDate) {
                try {
                    item.pubDate = new Date(item.pubDate);
                } catch (err) {
                    item.pubDate = "";
                }
            };
            item.contentSnippet = tryEval(article, "article.description[0]");
            if (item.contentSnippet.indexOf("<") > 0) {
                item.contentSnippet = item.contentSnippet.substring(0, item.contentSnippet.indexOf("<") - 1);
            };
            item.image = tryEval(article, "article['media:content'][0].$.url|article.thumbnail[0]");
            if (!item.image) {
                item.image = photoHunt(item);
                if (item.image) {
                    item.contentSnippet = "";
                }
            };
            if (item.title && item.link && (item.image || item.contentSnippet)) {
                return saveArticle(item);
            }
        }
        // unsure what your code intends if there was no article here
        // this will return undefined which will get filtered out later
    })
}

function saveArticle(article) {
    return new Promise(function(resolve, reject) {
        var curArticle;
        if (article._id) {
            curArticle = article;
            curArticle._id = article._id;           // don't know why this is needed since curArticle === article already
            curArticle.isNew = false;
        } else {
            curArticle = new Articles();
            curArticle.title = article.title;
            curArticle.link = article.link;
            curArticle.pubDate = article.pubDate;
            curArticle.image = article.image;
            curArticle.contentSnippet = article.contentSnippet;
            curArticle.sourceName = article.name;
            curArticle.sourceId = article.sourceId;
            if (article.haters) {
                curArticle.haters = article.haters;
            };
            if (article.lovers) {
                curArticle.lovers = article.lovers;
            };
            if (article.readers) {
                curArticle.readers = article.readers;
            };
        }
        curArticle.save(function (err) {
            if (err) reject(err) else resolve(curArticle);
        });
    });
};