Node.js: Mongoose initializeUnorderedBulk returning null
Some time ago I was able to write a method to bulk input a lot of information into my database. Now what I am trying to do is a method of clearing old records in 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 great. I then did this, hoping it would clear out old entries that I no longer need:
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 run these methods with this script that 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 starting my server, it gives a message that it cannot read the find property 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 as it works great with the bulkUpsert method, which is triggered by very similar code.
Does anyone know why this might be happening? Many thanks.
source to share
The problem is that mongoose has not yet connected to the database and therefore does not have a handle to the underlying driver object that you access through the accessory .collection
.
The mongoose methods themselves perform a little "magic", essentially queuing up all operations until the actual connection to the database is established. i.e:
Model.find().exec(function(err,docs) { }); // <-- callback queues until connection is ready
However, if there is no connection, the built-in methods will not return a collection object:
Model.collection.find({},function(err,docs) { }); <-- collection is undefined
The methods explained simply return a structure that has not been executed, so the error does not appear until you try to call a method on that structure.
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, while the "mongoose methods" do their own magic to "hide it", it is necessary when calling your own methods. The only way to avoid this is when you are absolutely sure that one of the "mongoose" methods is already running and that a connection has been made.
It's better to be safe than sorry, so it is a smart practice to expose your main program body and methods in a block like above.
source to share