Simant
Simant

Reputation: 4252

MongoError: Connection Closed By Application in MongoDB driver

While running the following code in NodeJS I am getting the error MongoError: Connection Closed By Application. I tried to resolve it but unable all the time. I need somebody's help...

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

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

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

    var firstState = '';
    var currentState='';
    var previousState='';
    var previousRecord='';

    cursor.each(function(err, doc) {
        if(err) throw err;
        if(doc == null) {
            return db.close();
        }

        currentState= doc['State'];
        previousState = previousRecord['State'];

        if(previousState === undefined) {           
            console.dir(currentState);
            firstState= doc['State'];

            db.collection('data').update({'_id' : doc['_id']}, {$set :{'month_high' : true}}, {'upsert' : true}, function(err, upserted){
                if(err) throw err;

                console.dir("Successfully upserted "+upserted + " document!");
            });

        } else if(currentState !=previousState){
                if (firstState!=currentState){                
                    console.dir(previousState);

                db.collection('data').update({'_id' : previousRecord['_id']}, {$set :{'month_high' : true}}, {'upsert' : true}, function(err, upserted){
                if(err) throw err;               

                console.dir("Successfully upserted "+upserted + " document!");
            });

                }
            }        

        previousRecord = doc;
    });
});

Upvotes: 0

Views: 1099

Answers (2)

Blakes Seven
Blakes Seven

Reputation: 50406

This is asynchronous code with asynchronous calls to the database, however the .each() iterator being used here does not wait for the contained callbacks to complete.

This is the primary cause of the error here, as the processing has not actually completed by the time the db.close() is being called. So this is what needs to be fixed.

Whilst a general clean-up of your code was certainly in order, the main things here are replacing that loop with stream processing, and also avoiding the "repeat yourself" calls to "update" by just altering the conditions and keeping the flow control in one place:

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

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

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

  var firstState = '',
    currentState='',
    previousState='',
    previousRecord='';


  cursor.on("end",function() {
    db.close();
  });

  cursor.on("err",function(err) {
    throw err;
  });

  cursor.on("data",function(data){
    cursor.pause();            // Stops events emitting on stream
    currentState = doc.State;
    previousState = previousRecord.State;

    var query =  { "_id": null };

    if (previousState === undefined) {           
      console.dir(currentState);
      firstState= doc.State;
      query._id  = doc._id;
    } else if(currentState != previousState) {
      if (firstState != currentState) {
        console.dir(previousState);
        query._id = previousRecord._id;
      }
    }        

    if (query._id != null) {
      db.collection('data').update(
        query, 
        { "$set":{ "month_high": true } },
        { "upsert": true },
        function(err, upserted){
          if(err) throw err;

          console.dir("Successfully upserted "+upserted + " document!");
          cursor.resume();     // resumes events on stream
          previousRecord = doc;

      });
    } else {
      cursor.resume();         // resumes events on stream
      previousRecord = doc;
    }

  });
});

The .pause() and .resume() methods there make sure that no new data is emitted in the stream until the current processing is done for the current document retrieved. This keeps your external variables in check.

Note that .resume() is also called "within" the callback to the .update() as you don't want to continue until this is returned as completed.

Upvotes: 1

Simant
Simant

Reputation: 4252

I rewrote the application implementing node stream interface which finally resolved the issue of "MongoError: Connection Closed By Application".

var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/weather', function(err, db) {   
     if(err) throw err;
     var data = db.collection('data');
     var options = { 'sort' : [['State', 1], ['Temperature', -1]] };
     var cursor = data.find({}, {}, options);

     var previousState='';  

    cursor.on("end", function(){
        db.close();
    });

    cursor.on("err", function(){
        console.dir("Error on:" + err);
        throw err;
    });

cursor.on("data", function(doc){
    cursor.pause();
    if(previousState != doc.State){
        previousState = doc.State;
        var query = { _id: doc._id};
        var operator = {$set: {month_high: true}};

        db.collection('data').update(query, operator, {'upsert' : true}, function(err, upserted){
          if(err){
                console.dir('Error : '+ err);
                throw err;
            } 
            console.dir("Successfully upserted "+ upserted + " document!");
            cursor.resume();
        });
    } else{
            cursor.resume();
    }
});

});

Upvotes: 0

Related Questions