Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js: Mongoose initializeUnorderedBulk returning null

a while ago I managed to write a method to bulk upsert many information into my database. Now what I am trying to do is a method to clean old records on the same database and table.

raidSchema.statics.bulkUpsert = function (raids, callback) {
  var bulk = Raid.collection.initializeUnorderedBulkOp();

  for (var i = 0; i < raids.length; i++) {
    var raid = raids[i];
    var date = new Date();
    bulk.find({id: raid.id, hash: raid.hash}).upsert().update({
      $setOnInsert: {
        ...
      },
      $set: {
        ...
      }
    });
  }

  bulk.execute(callback);
};

This works perfectly. Then I did this, in hope it would clean the old records that I don't need anymore:

raidSchema.statics.cleanOldRaids = function (callback) {
  var date = new Date();
  date.setMinutes(date.getMinutes() - 30);

  var bulk = Raid.collection.initializeUnorderedBulkOp();
  bulk.find({$or: [ { maxHealth: {$lte: 0} }, { isComplete: true }, {updatedOn: {$lte: date.getTime()}} ] }).remove();
  bulk.execute(callback);
};

And I am running this methods with this script, which tries to run it every 30 minutes:

var Raid = require('../models/raid');
var async = require('async');

var cleanInterval = 1000 * 60 * 30;

var cleanRaids = function () {
  console.log('cleanRaids: Starting cleaning');

  async.series([
      function (callback) {
        Raid.cleanOldRaids();
        callback(null, 'All servers');
      }],
    function (err, results) {
      if (err) throw err;

      console.log("cleanRaids: Done cleaning (" + results.join() + ")");
      setTimeout(cleanRaids, cleanInterval);
    })
};

cleanRaids();

but right after I run my server it crashes saying that it cannot read property find of undefined:

.../models/raid.js:104
  bulk.find({$or: [ { maxHealth: {$lte: 0} }, { isComplete: true }, {updatedO
       ^
TypeError: Cannot read property 'find' of undefined

I am completely lost since it works perfectly with the bulkUpsert method, which is run by a very similar code.

Anyone has any idea as to why this might be happening? Thanks a lot.

like image 605
Uriel Bertoche Avatar asked Aug 06 '15 10:08

Uriel Bertoche


1 Answers

The problem here is that mongoose has not connected to the database yet, and therefore has no handle to the underlying driver object you are accessing via the .collection accessor.

The mongoose methods themselves perform a little "magic", by essentially queuing all operations until the database connection is actually made. i.e:

Model.find().exec(function(err,docs) { });   // <-- callback queues until connection is ready

However if no connection is present, native methods will not return a collection object:

Model.collection.find({},function(err,docs) { }); <-- collection is undefined

The bulk methods just return a structure that has not executed, so the error does not present until you try to call a method on that stucture.

The fix is easy, just wait for the connection before executing any code:

mongoose.connection.on("open",function(err) {
  // body of program in here

});

So though "mongoose methods" do their own magic to "hide this away", this is needed when calling native methods. The only other way you get away with it is when you are absolutely sure that one of the "mongoose methods" has actually fired already, and that a connection has been made.

Better to be safe than sorry, so it is a wise practice to put the body of your main program initialize and methods within such a block as above.

like image 195
Blakes Seven Avatar answered Nov 26 '22 09:11

Blakes Seven