Honus Wagner
Honus Wagner

Reputation: 2908

Node.js + MongoDB update operation confirmation

In Node.js, I have (briefly) this script:

var http = require('http');
var XmlStream = require('xml-stream');
var mongo = require('mongodb');

var tims = { ... };

var db = new mongo.Db('tims', new mongo.Server("127.0.0.1", 27017, {}), {w: 1});
db.open(function(e, db) {
    var req = http.get({
        host: tims.uri,
        path: '/xml/'+tims.database+tims.services.database
    }).on('response', function(res) {
        res.setEncoding('utf8');
        cProjects = db.collection("projects");
        var xml = new XmlStream(res);

        xml.on('updateElement: Tims ProjectID', function(project) {
            // console.log(project.$text+' - '+project.$.title);
            cProjects.update({project_id: project.$text}, {project_id: project.$text, title: project.$.title}, {upsert:true}, function(err, result) {
                console.log('result: '+result);
            });     
        });

        xml.on('end', function(data) {
            db.close();
        });

    });
});

I am using a Node.js package called xml-stream that pieces together response chunks from Node to get valid XML before processing. My problem: if I leave out

xml.on('end', function(data) {
    db.close();
});

my connection never closes and the console just hangs. The upside is that console.log('result: '+result); writes to the console and I can see that my data was committed successfully. So if I leave in the end event and close the DB once all XML has been processed, the Node instance terminates before console.log('result: '+result) is written.

I am a newbie to both MongoDB and Node.js, so I was curious what the best practice is here for confirmation, or perhaps a simple pointing out of what I'm doing wrong.

Thanks for the help.

Upvotes: 2

Views: 423

Answers (1)

JohnnyHK
JohnnyHK

Reputation: 311855

Looks like the 'end' event is occurring before all the update callbacks have completed. So you need to rework your code a bit to keep track of the number of updates still pending and only call db.close() once both the 'end' event has fired and all the pending updates have completed.

So something like this:

db.open(function(e, db) {
    var req = http.get({
        host: tims.uri,
        path: '/xml/'+tims.database+tims.services.database
    }).on('response', function(res) {
        res.setEncoding('utf8');
        cProjects = db.collection("projects");
        var xml = new XmlStream(res);
        var end = false;
        var pending = 0;

        xml.on('updateElement: Tims ProjectID', function(project) {
            // console.log(project.$text+' - '+project.$.title);
            ++pending;
            cProjects.update({project_id: project.$text}, {project_id: project.$text, title: project.$.title}, {upsert:true}, function(err, result) {
                console.log('result: '+result);
                if (--pending === 0 && end) {
                    db.close();
                }
            });     
        });

        xml.on('end', function(data) {
            end = true;
        });

    });
});

Upvotes: 1

Related Questions