when passing two arguments to mongoose.connect
and expecting a promise to be returned, there is simply no promise returned and an error is thrown
for example:
await mongoose.connect(config.mongodb, config.mongodbOptions);
will throw the error
TypeError: this.$opPromise.then is not a function
at MongooseThenable.then (/Users/nexus/Public/crocodile/node_modules/mongoose/lib/index.js:785:26)
at process._tickDomainCallback (internal/process/next_tick.js:129:7)
at Module.runMain (module.js:606:11)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3
but without the second argument, it does not throw the error
await mongoose.connect(config.mongodb);
works fine
cc @vkarpov15
it looks like the alternate solution until this is fixed is to append the options to your URI such as
mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000
https://docs.mongodb.com/manual/reference/connection-string/#connections-connection-options
Not sure how to pass { server: ... }
server options in a URI - I don't think this is possible? Anyways another workaround is await mongoose.connect(config.mongodb, config.mongodbOptions).then;
which seems to work OK.
This happened to me when two test cases each tried to mongoose.connect(...)
. The second time it failed with the same error as in the first comment. The first connect was successful. Just FYI, I am using bluebird's Promise by setting mongoose.Promise.
I've worked around by preventing "double connect" in this particular case, but in general I'm not sure what the solution is or why it's failing like this.
Actually, I think it's one tiny bit more complicated. If you have:
mongoose.connection.on('error', err => { something(err); });
Then the failure to re-connect ("Trying to open unclosed connection.") does not throw, and in this scenario, mongoose.connect
fails to return a valid promise or promise-like object.
Without the error handler installed, the second connect will throw, and so there is no return value.
@niftylettuce can you provide a more thorough code sample and clarify which version of mongoose? I don't see any errors when I run:
'use strict';
var assert = require('assert');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/gh4659', { server: { reconnectTries: 5 } }).then(res => console.log(res));
@vkarpov15 you can see my issue here - https://github.com/crocodilejs/crocodile-node-mvc-framework/blob/development/src/helpers/mongoose.js - I have to add the .then
otherwise it does not work and gives this error
The issue is that mongoose.connect() does not return a promise when there's an error. If there's no 'on error' handler, then the method will throw, which hides the bug. If there's an error handler installed, it breaks.
See this line as an example of incorrect return value:
https://github.com/Automattic/mongoose/blob/master/lib/connection.js#L239
Here's a test case.
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
var url = 'mongodb://localhost/gh4659';
mongoose.connect(url)
.then(() => {
mongoose.connection.on('error', err => {
console.log('mongoose connection error: '+err);
});
console.log('connected - attempting reconnect');
return mongoose.connect(url);
})
.catch(err => {
console.log('rejected promise: '+err);
mongoose.disconnect();
});
;
Actually that example also covers it a bit because bluebird translates the exception thrown: this.$opPromise.then is not a function
into a rejection automatically - but you can see how it demonstrates the issue I hope. If you need further clarification I can rework this a bit more.
Thanks @vkarpov15