Mongoose Trying to open unclosed connection - node.js

This is a simplified version of the problem, but basically I'm trying to open 2 mongodb connections with mongoose and it's giving me "Trying to open unclosed connection." error.
Code sample:
var db1 = require('mongoose');
db1.connect('my.db.ip.address', 'my-db');
var db2 = require('mongoose');
db2.connect('my.db.ip.address', 'my-db');
db2.connection.close();
db1.connection.close();
Any idea how to make it work?

connect() opens the default connection to the db. Since you want two different connections, use createConnection().
API link: http://mongoosejs.com/docs/api.html#index_Mongoose-createConnection

To add on Raghuveer answer :
I would also mention that instead of using mongoose directly (you are probably using it this way you end up on this post) :
require('mongoose').model(...);
You would use the returned connection :
var db = require('mongoose').connect('xxx', 'yyy');
db.model(...);

I get this issue while running my tests.
This is what I did to solve it.
//- in my app.js file.
try {
mongoose.connect('mongodb://localhost/userApi2'); //- starting a db connection
}catch(err) {
mongoose.createConnection('mongodb://localhost/userApi2'); //- starting another db connection
}

I had this problem doing unit test with mocha.
The problem came when I added a second test because beforeEach is called twice.
I've solved this with this code:
const mongoose = require('mongoose');
describe('Your test suite', () => {
beforeEach( () => {
if (mongoose.connection.db) {
return; // or done();
} else {
// connect to mongodb
});
describe('GET /some-path', () => {
it('It should...', () => {
});
});
describe('POST /some-path', () => {
it('It should...', () => {
});
});
});
Hope it helps you!

You are attempting to open the default connection ( which is not yet closed ) a 2nd time.
do the following instead
var db = require('mongoose'); //note only one 'require' needed.
var connectionToDb1 = db.createConnection('my.db1.ip.address', 'my-db1');
var connectionToDb2 = db.createConnection('my.db2.ip.address', 'my-db2');

Using mongoose.disconnect(fn):
mongoose.disconnect(() => {
// here it would be possible "reset" models to fix
// OverwriteModelError errors
mongoose.models = {};
// here comes your logic like registering Hapi plugins
server.register(somePlugin, callback);
});
I found this question typing the error message and despite my problem is a bit different I believe it could be useful for those using Hapi. More specifically Hapi + rest-hapi + mocha.
When running mocha with --watch option I was facing both: OverwriteModelError and Error: Trying to open unclosed connection errors.

Simple Solution -
Use mongoose.createConnection() instead of mongoose.connect()
Its occurs because of version issue

Related

Jest test passed but get Error: connect ECONNREFUSED 127.0.0.1:80 at the end

I'm using node with TypeScript on my back end and Jest and Supertest as my test framework on my back end.
When I'm trying to test I have the result pass but I get an error at the end. Here's the result:
PASS test/controllers/user.controller.test.ts
Get all users
✓ should return status code 200 (25ms)
console.log node_modules/#overnightjs/logger/lib/Logger.js:173
[2019-12-05T04:54:26.811Z]: Setting up database ...
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.284s
Ran all test suites.
server/test/controllers/user.controller.test.ts:32
throw err;
^
Error: connect ECONNREFUSED 127.0.0.1:80
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1104:14)
npm ERR! Test failed. See above for more details.
Here's my test code:
import request from "supertest";
import { AppServer } from '../../config/server';
const server = new AppServer();
describe('Get all users', () => {
it('should return status code 200', async () => {
server.startDB();
const appInstance = server.appInstance;
const req = request(appInstance);
req.get('api/v1/users/')
.expect(200)
.end((err, res) => {
if (err) throw err;
})
})
})
Here's my server setup. I'm using overnightjs on my back end.
I created a getter to get the Express instance. This is coming from overnight.js.
// this should be the very top, should be called before the controllers
require('dotenv').config();
import 'reflect-metadata';
import { Server } from '#overnightjs/core';
import { Logger } from '#overnightjs/logger';
import { createConnection } from 'typeorm';
import helmet from 'helmet';
import * as bodyParser from 'body-parser';
import * as controllers from '../src/controllers/controller_imports';
export class AppServer extends Server {
constructor() {
super(process.env.NODE_ENV === 'development');
this.app.use(helmet());
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
this.setupControllers();
}
get appInstance(): any {
return this.app;
}
private setupControllers(): void {
const controllerInstances = [];
// eslint-disable-next-line
for (const name of Object.keys(controllers)) {
const Controller = (controllers as any)[name];
if (typeof Controller === 'function') {
controllerInstances.push(new Controller());
}
}
/* You can add option router as second argument */
super.addControllers(controllerInstances);
}
private startServer(portNum?: number): void {
const port = portNum || 8000;
this.app.listen(port, () => {
Logger.Info(`Server Running on port: ${port}`);
});
}
/**
* start Database first then the server
*/
public async startDB(): Promise<any> {
Logger.Info('Setting up database ...');
try {
await createConnection();
this.startServer();
Logger.Info('Database connected');
} catch (error) {
Logger.Warn(error);
return Promise.reject('Server Failed, Restart again...');
}
}
}
I read this question - that's why I called the method startDB.
So I figured out and the solution is quite easy. I can't explain why though.
This req.get('api/v1/users/') should be /api/v1/users - you need a leading /.
For Frontend...
If you are making use of axios and come across this error, go to the testSetup.js file and add this line
axios.defaults.baseURL = "https://yourbaseurl.com/"
This worked for me. So, typically, this is a baseURL issue.
I had this error in my React frontend app tests.
I was using React testing library's findBy* function in my assert:
expect(await screen.findByText('first')).toBeInTheDocument();
expect(await screen.findByText('second')).toBeInTheDocument();
expect(await screen.findByText('third')).toBeInTheDocument();
After I changed it to:
await waitFor(async () => {
expect(await screen.findByText('first')).toBeInTheDocument();
expect(await screen.findByText('second')).toBeInTheDocument();
expect(await screen.findByText('third')).toBeInTheDocument();
});
the error is gone.
I don't know exactly why, but maybe it will help someone
UPDATE: I was mocking fetch incorrectly, so my test called real API and caused that error
I put this line in my setupTests file:
global.fetch = jest.fn()
It mocks fetch for all tests globally. Then, you can mock specific responses right in your tests:
jest.mocked(global.fetch).mockResolvedValue(...)
// OR
jest.spyOn(global, 'fetch').mockResolvedValue(...)
Slightly different issue, but same error message...
I was having this error when using node-fetch when trying to connect to my own localhost (http://localhost:4000/graphql), and after trying what felt like everything under the sun, my most reliable solution was:
using this script in package.json: "test": "NODE_ENV=test jest --watch"
If the terminal shows connection error I just go to the terminal with Jest watching and press a to rerun all tests and they pass without any issue.
¯\_(ツ)_/¯
Success rate continued to improve by renaming the testing folder to __tests__ and moving my index.js to src/index.js.
Very strange, but I am too exhausted to look at the Jest internals to figure out why.
The rules for supertest are the same as the rules for express. OvernightJS does not require any leading or ending "/" though.
For anyone landing on this, but not having issues with trailing slashes:
jest can also return a ECONNREFUSED when your express app takes some time (even just a second) to restart/init. If you are using nodemon like me, you can disable restarts for test files like --ignore *.test.ts.
This error also occurs if you have not set up a server to catch the request at all (depending on your implementation code and your test, the test may still pass).
I didn't get to the bottom of this error - it wasn't related to the (accepted) leading slash answer.
However, my "fix" was to move the mocks up into the suite definition - into beforeAll and afterAll for cleanup between tests).
Before, I was mocking (global.fetch) in each test, and it was the last test in the suite to use the mock that would cause the error.
In my case, the issue was related to package react-inlinesvg. Package makes a fetch request to get the svg file and since server is not running, it gets redirected to default 127.0.0.1:80.
I mocked react-inlinesvg globally to output props including svg filename to assert in testing.
jest.mock('react-inlinesvg', () => (props) => (
<svg data-testid="mocked-svg">{JSON.stringify(props)}</svg>
));

voltdb-client-nodeJS doesn't work about #AdHoc proceduer

I followed the voltdb-client-nodeJS, and implement the #AdHoc query function, but the "read" function didn't callbacked, so that can't get any queried results, can't determine if the connection is successful, too.
[callProcedure code]
var query = resultsProc.getQuery();
query.setParameters(["select * from Q_SHIPPINGCARRIERHISTORY_STREAMING where TrackingNumber=431476575751"]);
client.call(query, function read(errorCode, eventCode, results){
...
}, function write(errorCode, eventCode, results){
...
});
[connect DB code]
var config = new VoltConfiguration();
config.host = "s7biapp26";
config.port = 8080;
var client = new VoltClient([config]);
client.connect(function(code, event, results){
...
});
On the second attempt, can't require('voltjs') or require('volt') after npm install voltjs(version:voltjs#0.2.0).
So, could you provide a more detailed documentation about the voltdb-client-nodeJS, or paste a simpler demo of #AdHoc, thank you very much!
The key is connected voltdb failed by error code in connect callback function, I tried to remove the port, then connected success!
The secondly, requiring the module should require('voltjs/lib/client').
referenced the links:
https://github.com/VoltDB/voltdb-client-nodejs/issues/12
https://forum.voltdb.com/forum/voltdb-discussions/building-voltdb-applications/577-nodejs-client-for-helloworld

Knex migration not working when using migration API

I am new to knex migrations and for the past 2 days I have been struggling to get it working but nothing happen. I am trying to run my migrations programmatically using the knex.migration object.
First using the cli, I create a migration file in the migrations directory. Here is its content:
exports.up = function(knex, Promise) {
return Promise.all([
knex.schema.createTable('users', function (table) {
table.increments('id').primary();
table.string('username');
table.string('password');
table.string('email');
table.string('name');
table.timestamp('date');
}),
]);
};
exports.down = function(knex, Promise) {
};
Then from my code I initialize the Knex object:
var knex = Knex({
client:'sqlite3',
connection:{
filename: './knex.sqlite'
}
});
Then I execute the migration:
knex.migrate.latest().then(()=>{
// console.log()
}).catch(err =>{
//
});
But absolutely nothing happens. My migration file is never executed and there is no error or warning message. So I don't know where to look at to start searching for the problem. When I look at my sqlite database, I can see that tables knex_migrations, knex_migrations_lock and sqlite_sequence have been created.
So what I am doing wrong here? Is there something I am missing?
Thanks for any suggestion
There's no requirement to use the CLI tools. Sometimes it's not possible to use it due to its limitations and in this case it's indeed possible to use the migration API directly, like so:
const knex = require('knex')({
// Here goes the Knex config
});
const migrationConfig = {
directory: __dirname + './migrations',
}
console.info('Running migrations in: ' + migrationConfig.directory);
knex.migrate.latest(migrationConfig).then(([batchNo, log]) => {
if (!log.length) {
console.info('Database is already up to date');
} else {
console.info('Ran migrations: ' + log.join(', '));
}
// Important to destroy the database, otherwise Node script won't exit
// because Knex keeps open handles.
knex.destroy();
});
There was two issues in the original question:
The migration directory was not specified - in this case Knex is not smart and will simply not do anything instead of throwing an error. Most likely the default used by Knex is not right so it's best to specify it.
knex.destroy() was missing. In this case, the script will never exit because Knex keeps open handles on the database, so it just looks like it's stuck doing nothing.
The above script also outputs more log info to see what's exactly happening.
Knex migrations are supposed to run by Knex CLI,FYI: https://knexjs.org/#Migrations
As your code described, I found a strange issue:
knex.migrate is actually undefined, it's not a property of knex.

mongoose setCurrentLogger does not work

I'm trying to change the mongoose console log printing using the setCurrentLogger function as described here and in the tutorial for older mongo driver here. I didn't find any instructions to do that with mongoose only with the native mongodb driver.
In order to test it, I just tried changing only the printed msg:
var mongoose = require('mongoose');
var MongoLogger = require('mongodb').Logger;
var MongooseLogger = mongoose.mongo.Logger;
MongoLogger.setCurrentLogger(function(msg, context) {
console.log('aaaaaa', context);
});
MongooseLogger.setCurrentLogger(function(msg, context) {
console.log('aaaaaa', context);
});
But it doesn't seems to work, I'm still getting the full error stack priting on console, instead of the expected aaaaaa.
The question is, how to change the logger function in mongoose like the setCurrentLogger function described for the native driver
I noticed it doesn't work unless you set the logger after connecting. And you need to set the log level too:
const Mongoose = require('mongoose');
const Logger = Mongoose.mongo.Logger;
Mongoose.connect(uri);
Logger.setLevel('debug');
Logger.setCurrentLogger(function(message, context) {
console.log(message);
});

Cannot overwrite `Kitten` model once compiled

I've run into an issue with the Mongoose Getting Started guide.
I have MongoDB running and everything is working perfectly until I add the last line:
Kitten.find({ name: /^Fluff/ }, callback)
When I node server.js I get this error:
OverwriteModelError: Cannot overwrite Kitten model once compiled.
Here's the full error and my server.js.
Any idea what I'm doing wrong?
P.S. I'm running node 10.26, npm 1.4.13, express 4.4.3 & mongoose 3.8.12 on OS X 10.9.3.
You get the error because callback in Kitten.find({ name: /^Fluff/ }, callback) calls var Kitten = mongoose.model('Kitten', kittySchema); again. Change
Kitten.find({ name: /^Fluff/ }, callback)
to something like:
Kitten.find({ name: /^Fluff/ }, function(err, kittens) {
});
It doesn't make sense to call the callback function again.
I thought this could be useful to someone else who tries it...
I started looking into mongoose and tried Getting Started guide. I don't see the above error happening where it was reported. However, I did see it intermittently. If it happens, follow #3 below. Here are my observations:
Issue#1. If I copy paste the whole code I see an issue with "I don't have a name" as the single quote in don't is not escaped.
Solution#1. I tried to escape with \ and \\ but it didn't work. Google search didn't help. After some research I found that it is forgiving for single quotes outside the function. But, inside the function it won't work. So, I defined a variable outside the function. Probably better to define strings in a separate document for localization anyways. Above all, it works. :)
Issue#2. I see the issue at
fluffy.speak();
TypeError: fluffy.speak is not a function
Here since the first 'mongoose.model(...)' doesn't have this method, adding it later and re-running 'mongoose.model(...)' will not help.
Solution#2. Comment the first 'mongoose.model(...)'
Issue#3. When I copy paste the code from the web site, it is causing weird errors.
Solution#3. Just deleted all the tabs and empty spaces at the end of lines in a Notepad++. That took care of it.
Here is the code that worked for me (Needless to say, if it doesn't work, please copy paste first in notepad):
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection.error:'));
db.once('open', function(callback) {
//yay!
});
var kittySchema = mongoose.Schema({
name: String
});
//var Kitten = mongoose.model('Kitten', kittySchema);
//var silence = new Kitten({ name: 'Silence' });
//console.log(silence.name);
//console.log(silence);
var noname = "I don't have a name";
kittySchema.methods.speak = function () {
var greeting = this.name
? "Meow name is " + this.name
: noname;
console.log(greeting);
}
var Kitten = mongoose.model('Kitten', kittySchema);
var fluffy = new Kitten({ name : 'fluffy' });
fluffy.speak();

Resources