-2

I have a small program that reads each of the record and update each of the record. Given the async nature of node and callback. what is the efficient and the correct way to close the db connection?

Sample Program:

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

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

    var query = { };
    // get all the students in the database 
    var cursor = db.collection('students').find(query);

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

        if(doc == null) {
            return;
        }

        // filter out only the homework scores
        var homeworksOnly = doc.scores.filter(function(scores){
            if (scores.type === "homework") return true;
            return false;
        })

        // filter out the non homework scores
        var notHomeWorks = doc.scores.filter(function(scores){
            if (scores.type !== "homework") return true;
            return false;
        })

        // sort the homework score to remove the min score from the list.
        homeworksOnly.sort(function(a,b){
            if (a.score > b.score) return 1;
            if (b.score > a.score) return -1;
            return 0;
        });

        console.log("Before removing the min score"+doc._id);
        console.dir(homeworksOnly);
        console.log("After removing the min score"+doc._id);
        homeworksOnly.splice(0,1);
        console.dir(homeworksOnly);
        console.log("Merge the homework with other scores"+doc._id);
        var newScores = homeworksOnly.concat(notHomeWorks);
        console.dir(newScores);
        console.log("*****");

        // Now update the database for this student with the new scores
        var search = {"_id":doc._id};
        var operator = { '$set' : { 'scores' : newScores } };

        db.collection('students').update(search, operator, function(err, updated) {
            if(err) throw err;

            updateCount++;
            console.dir("Successfully updated " + updated + " document! count: "+updateCount);
        });

    });
});

Now the program works but I need to hit the Ctrl+C to terminate the program. Is there a way to know that all the callbacks have completed so that the program can be terminated?

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • 1
    You will kick yourself when the answer to the homework problem from thee MongoDB course you are trying to solve for the course is actually revealed to you. The actual answer is a lot more simple than how you approached this. – Blakes Seven Aug 19 '15 at 03:53
  • Thanks Blakes, I am not trying to find the answer for the hw1, I have already got that. I have seen the same problem with my other samples. I haven't found a concrete answer. – Santhosh Kumar Aug 19 '15 at 07:52
  • 1
    Not sure why the question is down voted. Just because there are some know it all does not mean everyone in the world need to know all the answers. There are several self taught people and every one starts from unknown. – Santhosh Kumar Aug 19 '15 at 15:42
  • I really don't think it was about the database closure question itself but more about the fact that you are posting something that basically answers a question asked of an online course that is meant to be solved and not looked up. Other people here are aware of the course and content. It was really only because this is not the most "optimal" solution that one of those votes is not in fact mine. – Blakes Seven Aug 19 '15 at 23:17
  • Thanks Blakes, I get your point, what is wrong with asking question on something to get more clarity, if it were just for the course I don't even have to worry about having to close the db. In fact as someone has pointed out there are other modules that get things done better, faster, but your reply made me more aware to the on call functions, which are eye opener for a beginner to learn better. so appreciate all the efforts from the expects to clarify and provide better clarity. – Santhosh Kumar Aug 20 '15 at 17:46

2 Answers2

0

After the update statement is done use

db.collection('students').update(search, operator, function(err, updated) { if(err) throw err;

    updateCount++;
    console.dir("Successfully updated " + updated + " document! count: "+updateCount);
});

db.close();

  • Read about [asynchronous programming](http://stackoverflow.com/questions/16336367/what-is-the-difference-between-synchronous-and-asynchronous-programming-in-node) to understand how wrong you are. – Blakes Seven Aug 19 '15 at 04:04
  • this will result in the socket closed error, as this is still inside a cursor. – Santhosh Kumar Aug 19 '15 at 07:54
0

There are better libaries you can integrate with nodejs to handle the callback flow better, but simply working with the basic driver as a dependency, all you need is the basic node stream interface which is already built in to the cursor.

This allows .pause() and .resume()for flow control when processing, and an "end" event when the cursor stream is complete:

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

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

    var query = { };
    // get all the students in the database 
    var cursor = db.collection('students').find(query);

    // called on errors
    cursor.on("error",function(err) {
      throw err;
    });

    // called on stream complete
    cursor.on("end",function() {
      db.close();
    });

    // process each document in the stream
    cursor.on("data",function(data) {

        cursor.pause();     // stops the cursor stream while processing

        // filter out only the homework scores
        var homeworksOnly = doc.scores.filter(function(scores){
            if (scores.type === "homework") return true;
            return false;
        })

        // filter out the non homework scores
        var notHomeWorks = doc.scores.filter(function(scores){
            if (scores.type !== "homework") return true;
            return false;
        })

        // sort the homework score to remove the min score from the list.
        homeworksOnly.sort(function(a,b){
            if (a.score > b.score) return 1;
            if (b.score > a.score) return -1;
            return 0;
        });

        console.log("Before removing the min score"+doc._id);
        console.dir(homeworksOnly);
        console.log("After removing the min score"+doc._id);
        homeworksOnly.splice(0,1);
        console.dir(homeworksOnly);
        console.log("Merge the homework with other scores"+doc._id);
        var newScores = homeworksOnly.concat(notHomeWorks);
        console.dir(newScores);
        console.log("*****");

        // Now update the database for this student with the new scores
        var search = {"_id":doc._id};
        var operator = { '$set' : { 'scores' : newScores } };

        db.collection('students').update(search, operator, function(err, updated) {
            if(err) throw err;

            updateCount++;
            console.dir("Successfully updated " + updated + " document! count: "+updateCount);

            cursor.resume();        // restarts the stream processing now we are done
        });

    });

});
Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • Thanks Blakes, will try this out today evening, I feel like kicking myself for sure :), having failed to look into the on. functions, being in the node environment. I will have this answer marked as correct, once I confirm. Thanks for you detailed answer. – Santhosh Kumar Aug 19 '15 at 07:58