2013-06-05 30 views
5

Tôi đang học nút, diễn đạt, mongo và, trong quá trình này, javascript. Tôi đang cố gắng để có được một tính năng mà sử dụng rssparser, có được một danh sách các câu chuyện và lưu chúng vào một cơ sở dữ liệu mongo với mongoose.Gặp sự cố khi lặp qua mảng và lưu vào phần đuôi. Sự cố gọi lại?

Tôi đã kéo RSS hoạt động và tôi đang lặp qua các câu chuyện, đó là mục mà tôi đang gặp sự cố. Tôi muốn 1) kiểm tra xem câu chuyện chưa tồn tại trong cơ sở dữ liệu chưa, và 2) nếu không, hãy lưu nó. Tôi nghĩ rằng tôi đang bị mất theo cách gọi lại được xử lý. Đây là mã hiện tại của tôi, có nhận xét.

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

    } 
}); 

Khi điều này chạy, những gì tôi thấy là rất nhiều giao diện điều khiển đầu ra:

Nó bắt đầu hiển thị tất cả những câu chuyện (nhiều bỏ qua):

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 

Sau đó, tiếp tục tương tự (nhiều bỏ qua):

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 }                  

Nó lặp lại tiêu đề "sắp lưu" (câu chuyện cuối cùng trong nguồn cấp dữ liệu) và nó lưu câu chuyện một lần, giống như hàng cuối cùng hiển thị.

Đầu ra console.log chỉ hiển thị cho tôi, tất cả đầu ra tiêu đề câu chuyện ở trên cùng, sau đó tất cả nội dung từ bên trong cuộc gọi query.exec() ở dưới cùng.

Any help is appreciated ...

Trả lời

1

Vấn đề với điều này là những câu chuyện được tham chiếu trong khi gọi lại exec sẽ được thiết lập để bất cứ điều gì là điều cuối cùng lặp trên trong vòng lặp for, khi gọi lại sẽ nhận được được thực hiện, vì tất cả các hàm được thực thi đều tham chiếu cùng một biến của biến.

Cách đơn giản nhất để khắc phục điều này chỉ đơn giản là quấn mỗi điều trong vòng lặp for trong một chức năng mà bạn thực hiện ngay lập tức với các thông số, như trong:

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

tôi đã không kiểm tra này, nhưng tôi chắc chắn bạn sẽ thấy rằng nó sẽ khắc phục sự cố của bạn

Một cách dễ dàng hơn, sạch hơn, tốt hơn là lặp lại các mục trong vòng lặp forEach trên mảng, nếu nền tảng của bạn hỗ trợ (node.js nào hiện) - phiên bản này thậm chí còn đẹp hơn:

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

Tôi đã triển khai phương pháp dọn dẹp và nó hoạt động rất tốt, cảm ơn bạn. Vậy vấn đề của tôi chỉ là vấn đề thời gian? tức là, tất cả các mục trong out.items đã được lặp lại trước khi cuộc gọi lại đó được thực thi (do đó câu chuyện được đặt thành out.item cuối cùng)? – Mike

+0

Vấn đề của bạn phải làm với phạm vi, dẫn đến tình trạng chạy đua. khi vòng lặp for lặp qua, chỉ có một tham chiếu đến 'story', và nó được ghi đè mỗi khi bạn lặp qua mảng đó. Nếu chức năng exec đã được thực hiện ngay lập tức, đồng bộ, mã của bạn sẽ hoạt động tốt, nhưng vì tất cả các cuộc gọi đến gọi lại trong exec xảy ra sau khi vòng lặp for đã kết thúc, tất cả chúng đều là trường hợp cuối cùng của câu chuyện được gán cho biến câu chuyện. khi chúng được "đóng cửa" với một hàm, tất cả chúng đều có thể hiện riêng của 'câu chuyện'. đây là một sai lầm rất phổ biến – arnorhs

2

cũng, nút là máy chủ điều khiển sự kiện và javascript cũng là sự kiện điều khiển, vì vậy bạn có thể gọi công cụ không đồng bộ.

bạn cần sử dụng một số mẫu không đồng bộ để thực hiện những gì bạn muốn.

đầu tiên, nếu bạn đang sử dụng mongoose bạn có thể sử dụng nó là lớp schema để kiểm tra các chỉ tiêu đã tồn tại mà không yêu cầu db một lần nữa:

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 là duy nhất, do đó tiết kiệm được sẽ gây ra một bản sao lỗi và mongoose sẽ không lưu truy vấn.

nay đến lặp qua các mục và tiết kiệm mỗi người chúng ta cần một số loại của một mô hình cho nó, may mắn là chúng tôi có async cho nó:

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

chúng tôi sử dụng async trong một chế độ song song như chúng ta làm không cẩn thận nếu một số trùng lặp hay không. bạn cũng có thể theo dõi nó với một mảng mà bạn có thể đẩy nó vào sai || kết quả là bạn có thể xem có bao nhiêu mục bạn đã lưu.

+0

Xin chào, cảm ơn, đó có thể là cách tốt hơn để đạt được mục tiêu. Nhiều đánh giá cao! – Mike

Các vấn đề liên quan