2014-11-05 62 views
0

我有以下從查詢它通過市,然後溫度排序collectoin創建光標簡單的Node.js應用程序時,通過應用程序錯誤關閉。之後,我遍歷遊標並通過添加最高值:true來爲每個城市更新每個城市最高氣溫的每個文檔。連接通過光標迭代和更新文件

var MongoClient = require('mongodb').MongoClient; 

MongoClient.connect('mongodb://localhost:27017/temp', function(err, db) { 
    if(err) throw err; 

    var cursor = db.collection('data').find().sort({ City : 1, Temperature : -1 }); 

    var previous = ''; 

    cursor.each(function(err, doc) { 
     if(err) throw err; 

     if(doc == null) { 
      console.dir("Closing database connection"); 
      return db.close(); 
     } 
     if (previous != doc.City) { 
      previous = doc.City; 

      var query = { _id : doc._id }; 
      var operator = { '$set' : { highest : true } }; 

      console.dir(doc.City + " is " + doc.Temperature + "; "); 


      db.collection('data').update(query, operator, function(err, updated) { 
       if(err) { 
        console.error('Error:', err); 
        throw err; 
       } 


       console.dir("Successfully updated: " + JSON.stringify(updated));  
      });  
     } 
    }); 

}); 

這裏的問題是,只有第一個城市得到適當的更新,這裏是輸出:

'Berlin is 81; ' 'Successfully updated: 1' 'Paris Florida is 83; ' 'Warsaw New Mexico is 57; ' 'Barcelona Vermont is 57; ' 'Closing database connection' Error: { [MongoError: Connection Closed By Application] name: 'MongoError' } Error: { [MongoError: Connection Closed By Application] name: 'MongoError' } Error: { [MongoError: Connection Closed By Application] name: 'MongoError' }

我對所發生的事情的猜測是:將光標經過所有文件上的那些要求更新最高溫度:

db.collection('data').update(query, operator, function(err, updated) 

但回調返回,光標完成之前迭代和該片段的代碼被稱爲封閉連接:

if(doc == null) { 
      console.dir("Closing database connection"); 
      return db.close(); 
     } 

之後,所有未完成處理的更新都會出錯,因爲沒有數據庫連接可用。

使連接所有文件都成功更新後,才關閉有什麼處理它的正確方法?

回答

2

尼爾提到的,我們可以用.stream(),但我可以使程序執行通過計算已經處理的更新和關閉,我們期待更新更新所有文件後,數據庫連接預期。 在我的情況下,這是非常簡單的,因爲我已經在數據庫中只有4個城市,所以我預計只有4個文件進行更新。我們也可以通過查詢和計算結果獲得這個數字,但這對我來說已經足夠了。

這裏的工作代碼:

var MongoClient = require('mongodb').MongoClient; 

MongoClient.connect('mongodb://localhost:27017/temp', function(err, db) { 
    if(err) throw err; 

    var cursor = db.collection('data').find().sort({ City : 1, Temperature : -1 }); 

    var previous = ''; 
    var updatedCount = 0; 
    var expectedToUpdate = 4; // Hardcoded, but we might want to obtain it pragmatically 

    cursor.each(function(err, doc) { 
     if(err) throw err; 

     if(doc == null) { 
      return 
     } 
     if (previous != doc.City) { 
      previous = doc.City; 

      var query = { _id : doc._id }; 
      var operator = { '$set' : { highest : true } }; 

      console.dir(doc.City + " is " + doc.Temperature + "; "); 


      db.collection('data').update(query, operator, function(err, updated) { 
       if(err) { 
        console.error('Error:', err); 
        throw err; 
       } 


       console.dir("Successfully updated: " + JSON.stringify(updated));  
       updatedCount++; 
       if (updatedCount == expectedToUpdate) { 
        console.dir("updated expected number of documents. Closing db."); 
        db.close(); 
       } 
      });  
     } 
    }); 

}); 
1

我通常發現node stream接口是一個迭代器是更好的選擇。有光標對象上的.stream()方法爲這樣:

var stream = db.collection('data').find().sort( 
    { City : 1, Temperature : -1 } 
).stream(); 

stream.on('data',function(data) { 
    // do things with current document 
    // but pause on things with a callback then resume; 

    stream.pause(); 
    db.collection('data').update(query, operator, function(err, updated) { 
     // resume the stream when this callback is done 
     stream.resume(); 
    }) 
}); 

stream.on('end',function() { 
    // Called when everything is complete 
    // db.close is safe here as long as you are no longer using the connection 
    db.close(); 
}); 

在從本機驅動程序的version 2.0事實流接口是默認的光標對象的一部分。

但在一般情況下,只能打電話db.close()用於一次性處理腳本。您通常不應該在服務器類型實現中調用它,而只是在整個生命週期中將連接打開。