How to handle errors using the Tedious driver with Node - node.js

The Problem:
I keep running into issues with typos in my SQL queries and the tedious driver isn't helping much. When there are errors, it does a fine job telling me the type of error and what went wrong, but the stack trace never contains any of my project files. This is making it difficult to debug, especially when I'm making multiple queries in the same function. I'm currently using the mssql library, but experienced the same problem using tedious directly. Plus, mssql isn't mentioned in the error's stack at all, so I figure it's not the problem.
What I've Tried:
Looking for issues on the tedious GitHub page
Added a conn.on('error') listener, which doesn't appear to do anything.
Added process.on() listeners for 'uncaughtException' and 'unhandledRejection'.
Moved the initialization of the ConnectionPool into it's own function to try and catch the error there. No luck.
Some Code:
Here's a barebones example of what I'm using to run the queries:
async function dbConnect() {
const conn = await new ConnectionPool(dbConfig).connect();
conn.on('error', error => {
console.error('*Connection Error:', error);
});
return conn;
}
async function runQuery() {
const conn = await dbConnect();
await conn.request().query(`SELECT Thing FROM Place`);
await conn.close();
}
runQuery()
.then(results => {
console.log(results);
process.exit(0);
})
.catch(error => {
console.error(error);
process.exit(1);
});
The Error:
Hopefully, this is something that's possible. If not, is there a different Node driver for SQL Server that someone's come up with?
Edit: Added an error listener on request
async function dbConnect() {
const conn = await new ConnectionPool(dbConfig).connect();
const request = new Request(conn);
conn.on('error', error => {
console.error('*Connection Error:', error);
});
request.on('error', error => {
console.error('*Request Error:', error);
});
return request;
}
async function runQuery() {
const request = await dbConnect();
await request.query(`SELECT Thing FROM Place`);
}

Related

Mongoose connection to Mongo DB: Best practice for exception cases

It's not clear how to best trap errors using "mongoose.createConnection"
The Mogoose docs are pretty good at explaining how to trap an initial connection error when using "mongoose.connect" ... excerpt from docs., below:
mongoose.connect('mongodb://localhost:27017/test').
catch(error => handleError(error));
// Or:
try {
await mongoose.connect('mongodb://localhost:27017/test');
} catch (error) {
handleError(error);
}
However, in the case of "mongoose.createConnection" (neeed for more than one DB) ... this strategy does not seem to work. Here is what I've tried
const Db = mongoose.createConnection(dbUrl);
try {
await Db;
} catch (error) {
console.log(Error Connecting to DB");
}
which results in:
"SyntaxError: await is only valid in async functions and the top level bodies of modules"
Any pointers, please?
Thanks,
Tim.
Update following Anshu's post:
After making the changes, per Anshu, I then called the function
connectFunction()
and everything seemed OK, but only until the code reached the following line:
const Data = Db.model(`someCollection`, someSchema);
where it complained that "Db" is not defined. Presumably, because it is only scoped within the function? It feels like a chicken and egg situation. Any further guidance, please?
Update 11/18/22:
After making the following change:
async function connectFunction(){
try {
var db = await mongoose.createConnection(dbUrl);
} catch (error) {
console.log(Error Connecting to DB");
}
... same issue. I'm using VS Code and as a trivial observation, it colorizes variables, etc. In this case the variable "db" is "grayed out", i.e. it has recognized that something is wrong.
Update#2 11/18/22: I was able to make the "db is not defined error" go away once I realized I needed a return in the function. This is the latest code:
async function connectToBrandDb(url) {
try {
var Db = await mongoose.createConnection(url, {
keepAlive: true,
keepAliveInitialDelay: 300000,
serverSelectionTimeoutMS: 5000 });
}
catch (error) {
console.log(`Error Connecting To DB`);
}
return Db;
}
const brandDb = connectToBrandDb(dbUrl);
var Data = brandDb.model(`someCollection`, someSchema);
... and now looking at this from the terminal:
var Data = brandDb.model(`someCollection`, someSchema);
^
TypeError: brandDb.model is not a function
You should use async keyword before functions when you're trying to use await inside them. You cannot use await at the top (outside async function), so that's what the error is telling.
async function connectFunction() {
try {
const db = await mongoose.createConnection(dbUrl);
} catch (error) {
console.log("Error Connecting to DB");
}
}

NodeJS - mysql connection exceptions not caught

I am new to Node.js and I have the following code below:
const mysql = require('mysql');
async function insertNewRecord(record) {
const connectionUrl = 'mysql://root:mypassword#mydatabasehost:3306/mydb';
const pool = mysql.createPool(connectionUrl);
pool.on('connection', function (conn) {
console.log('*******on connection***********');
});
pool.on('error', function () {
console.log('****POOL CONNECTION ERROR***');
});
await pool.query('INSERT INTO users SET ?', record);
}
async function doProcess() {
try {
//construct record object
insertNewRecord(record)
} catch (error) {
console.log(error);
}
}
I purposely used the wrong database host name to see if the error would be caught and logged, but I saw no log. I was expecting to see POOL CONNECTION ERROR in the logs but it didn't show up. No error was caught either from the catch statement.
Am I doing something wrong? I did my own research and the pool.on lines you see in the codes is what I have tried to add, but doesn't seem to work. Am I doing error handling the correct way?
insertNewRecord(record) is an asynchronous function. If you don't use await with it node won't wait for the function to complete, and you won't see the error.

TypeError: getDb is not a function

I need your help on this error "TypeError: getDb is not a function"
I am using Mongodb v3.0 or later
Node.js
I have this Error when creating an item.
See the portion of code with the error below
save() {
const db = getDb();
return db.collection('products')
.insertOne(this)
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
});
}
}
Whenever you connect with mongodb.MongoClient, you need to specify database to be use. So, getDb() should be like this:
return new Promise((resolve, reject) => {
mongodb.MongoClient.connect("URL", function (err, db) { //Use your conn URL
if(err)
reject(err);
resolve(db.db("database")); //Use your DB name
});
I think this would resolve your query. As without seeing getDB(), I can only help you with this. For next time, try to add require info so that other can understand or reproduce same.
_db = client.db('nodeShop'); // nodeShop is the name of the database.

How to use async/await with mongoose

In node.js I had code like following:
mongoose.connect(dbURI, dbOptions)
.then(() => {
console.log("ok");
},
err => {
console.log('error: '+ err)
}
);
Now i want to do it with async/await syntax. So i could start with var mcResult = await mongoose.connect(dbURI, dbOptions);, afaik it will wait for operation, until it ends with any result (much like calling C function read() or fread() in syncronous mode).
But what should I write then? What does that return to the mcResult variable and how to check for an error or success? Basically I want a similar snippet, but written with proper async/await syntax.
Also I wonder because I have auto reconnect, among dbOptions:
dbOptions: {
autoReconnect: true,
reconnectTries: 999999999,
reconnectInterval: 3000
}
Would it "stuck" on await forever, in case if database connection is unavailble? I hope you can give me a clue on what would happen and how that would work.
Basically I want a similar snippet, but written with proper async/await syntax.
(async () => {
try {
await mongoose.connect(dbURI, dbOptions)
} catch (err) {
console.log('error: ' + err)
}
})()
Please try this, Below code has basics of db connectivity and a query :
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let url = 'mongodb://localhost:27017/test';
const usersSchema = new Schema({
any: {}
}, {
strict: false
});
const Users = mongoose.model('users', usersSchema, 'users');
/** We've created schema as in mongoose you need schemas for your collections to do operations on them */
const dbConnect = async () => {
let db = null;
try {
/** In real-time you'll split DB connection(into another file) away from DB calls */
await mongoose.connect(url, { useNewUrlParser: true }); // await on a step makes process to wait until it's done/ err'd out.
db = mongoose.connection;
let dbResp = await Users.find({}).lean(); /** Gets all documents out of users collection.
Using .lean() to convert MongoDB documents to raw Js objects for accessing further. */
db.close(); // Needs to close connection, In general you don't close & re-create often. But needed for test scripts - You might use connection pooling in real-time.
return dbResp;
} catch (err) {
(db) && db.close(); /** Needs to close connection -
Only if mongoose.connect() is success & fails after it, as db connection is established by then. */
console.log('Error at dbConnect ::', err)
throw err;
}
}
dbConnect().then(res => console.log('Printing at callee ::', res)).catch(err => console.log('Err at Call ::', err));
As we're talking about async/await then few things I wanted to mention - await definitely needs it's function to be declared as async - otherwise it would throw an error. And it's recommended to wrap async/await code inside try/catch block.
const connectDb = async () => {
await mongoose.connect(dbUri, dbOptions).then(
() => {
console.info(`Connected to database`)
},
error => {
console.error(`Connection error: ${error.stack}`)
process.exit(1)
}
)
}
connectDb().catch(error => console.error(error))
Lets assume the use of then() is prohibited, you can result to this...
const connectDb = async () => {
try {
await mongoose.connect(dbConfig.url, dbConfigOptions)
console.info(`Connected to database on Worker process: ${process.pid}`)
} catch (error) {
console.error(`Connection error: ${error.stack} on Worker process: ${process.pid}`)
process.exit(1)
}
}

mongoose.connection.collections.collection.drop() throws error every other time

I am setting up testing using Jest for an Node/Express/Mongo project. I have tried to write a function to clear collections so each test starts with a clean slate:
const clearCollection = (collectionName, done) => {
const collection = mongoose.connection.collections[collectionName]
collection.drop(err => {
if (err) throw new Error(err)
else done()
)
}
beforeEach(done => {
clearCollection('users', done)
})
And another try, with promises:
const clearCollection = collectionName => {
const collection = mongoose.connection.collections[collectionName]
return collection.drop()
}
beforeEach(async () => {
await clearCollection('users')
})
The problem is that it they both alternate between working and throwing an error. Every time I save the file, it either works perfectly, or throws an error, alternating each time. The errors are always either one of:
MongoError: cannot perform operation: a background operation is currently running for collection auth_test.users
MongoError: ns not found
I can get it to work 100% of the time (limited by the stack anyway) by making clearCollection() call itself inside a catch(), but this feels so wrong:
const clearCollection = collectionName => {
const collection = mongoose.connection.collections[collectionName]
return collection.drop()
.catch(() => clearCollection(collectionName))
}
I don't know why mongoose.connection.collections.<collection>.drop() randomly throws errors, but there is a simple way to remove all the documents in Mongoose, which works just fine for resetting the collection before tests:
beforeAll(async () => {
await User.remove({})
})
Works every time.
I was having a similar issue while trying to drop the database in the beginning of the tests and populating the database right after. In the first run, collections would be created; in the next one, I would get an error of 'database is in the process of being dropped.'; ...and it was alternating like this.
I was also using an "in memory" Mongodb, running $ run-rs -v 4.0.0 -s (https://www.npmjs.com/package/run-rs) in a separate terminal window before running my Mocha tests. Also, I have Mongoose 5.2.0 and Mocha 5.1.1 here.
I've found out that Mongoose not necessarily executes the the drop commands immediately. Instead, it will schedule them for when the connection is up.
So, there can be a race condition in which the promise of the drop command is resolved and you move on in the code until reaching the instruction for creating your collections... but the drop command didn't finish running yet, and you'll get the error for the creation the new collections. The drop finish running and for the next time you run your test, your database (or collection) is already dropped, and hence you'll be able to insert the new collections again.
So, this is how I've solved...
Run in the before hook:
test.dropDb = function(done) {
this.timeout(0)
let database = your_MongoDB_URI
mongoose.connect(database, function (err) {
if (err) throw err;
mongoose.connection.db.dropDatabase(function(err, result){
console.log('database dropping was scheduled');
});
})
mongoose.connection.on('connected', function() {
setTimeout(function(){ done() }, 3000);
});
}
Run in an nested before hook
test.createDb = function(done) {
this.timeout(0)
let createDb = require('./create-db.js')
createDb() // here I call all my MyCollections.insertMany(myData)...
.then( function() {
done()
})
.catch( function(err) {
assert( null == err)
});
}
Run in the after hook
test.afterAll = function(done) {
mongoose.connection.close()
.then( function() {
done()
})
}
I don't know why I had to explicitly close the connection in the after hook. I guess it has something to do with the way run-rs is programmed, but I didn't look into it. I just know that, in my case, closing the connection after the test was mandatory to get the expected behavior.

Resources