在遍历数组和保存到mongoose时遇到麻烦.回调的问题
Having trouble iterating through array and saving to mongoose. Callback issue?
我正在学习node, express, mongo,在这个过程中,还有javascript。我正试图获得一个功能,使用rssparser,获得一个故事列表,并将它们保存到mongoose数据库。
我已经让RSS pull工作了,并且我正在迭代故事,这是我遇到问题的保存。我想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 }
它重复"about to save"标题(这是提要中的最后一个故事),并保存该故事一次,如最后一行所示。
console.log的输出显示了我所放置的内容,所有的故事标题输出在顶部,然后query.exec()调用中的所有内容在底部。
这样做的问题是,一旦执行回调,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);
});
}
});
});
});
node是事件驱动的服务器,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不会保存查询。
现在要遍历项并保存每个项我们需要某种模式,幸运的是我们有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
});
}
我们在并行模式下使用async,因为我们不关心一些是否重复。你也可以用一个数组来跟踪它,你可以把err ||结果推给它您可以看到您保存了多少项。
- 使用JavaScript获取Google地图上显示的所有推文时遇到麻烦
- 在 Javascript 中添加数字时遇到麻烦
- 使用 Coffeescript 和 Express .js 将变量传递给 Jade 时遇到麻烦
- 编写正确的 jQuery 插件时遇到麻烦
- 在三.js中更改纹理时遇到麻烦
- 从 javascript 中的函数返回时遇到麻烦
- 理解 $.ajax() 参数以获取 PHP 变量时遇到麻烦
- 比较数组时遇到麻烦
- 使 JavaScript 函数工作时遇到麻烦
- 在Firefox和IE中获取CSS属性时遇到麻烦
- 将 Blueimp Gallery 与 HTML 和 Bootstrap 集成时遇到麻烦
- 将jQuery导入WordPress时遇到麻烦
- 在解决来自 coderbyte 的 JavaScript 编码挑战时遇到麻烦
- 从页面抓取时遇到麻烦
- 让jQuery在Wordpress中工作时遇到麻烦
- 当我使用Web SQL时,我遇到了麻烦
- 在codeigniter框架中添加css和js文件时遇到麻烦
- 处理由dayClick返回的日期时遇到麻烦
- 在使用jQuery更改依赖于滚动位置的类时遇到麻烦
- 在使用javascript加速滚动动画时遇到麻烦