Mongoose connection to Mongo DB: Best practice for exception cases - node.js

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");
}
}

Related

Function that return undefined in node.js. Inside the function I have mongoDB.connect

I tried to make function for my project in the service. This service need to check is user exists in my database, but my function(this function is checking) inside the class return undefined.
This is my code:
const express = require("express");
const mongoDB = require('mongodb').MongoClient;
const url = "here I paste url to my databse(everything is good here)";
class CheckService {
isUserExists(username) {
mongoDB.connect(url, (error, connection) => {
if (error) {
console.log("Error", '\n', error);
throw error;
}
const query = {name: username};
const db = connection.db("users");
const result = db.collection("users").find(query).toArray(
function findUser(error, result) {
if (error) {
throw error;
}
const arr = [];
if (result.value === arr.value) {
console.log(false);
connection.close();
return false;
} else {
console.log(true);
console.log(arr);
console.log(result);
connection.close();
return true;
}
});
console.log(result);
});
}
}
module.exports = new CheckService();
I imported my service to another service:
const checkService = require('./check.service');
After this, I invoked my function from my service like this:
console.log('function:',checkService.isUserExists(username));
I expected good result, but function doesn't return, that I want, unfortunately.
Please help!
There are two problems with your function
it doesn't return anything
toArray() is a promise, so your console.log probably just prints a promise.
Probably you're looking for something like this:
class CheckService {
async isUserExists(username) {
const connection = await mongoDB.connect(url);
const query = {name: username};
const db = connection.db("users");
const result = await db.collection("users").find(query).toArray();
connection.close();
return result.length !== 0;
}
}
You'd then invoke it with something like
await new CheckService().isUserExists(username);
Though, it's worth noting that you probably don't need toArray and instead could use findOne or even count() since all you care about is existence. I probably also wouldn't instantiate a new connection each time (but that's not super relevant)
2 things wrong here. Firstly the first comment is correct. You're only logging the result and not passing back to the caller. Secondly, a quick peek at the mongo docs shows that retrieval methods are promises. You need to make the function async and add awaits where needed.
Mongo:
https://www.mongodb.com/docs/drivers/node/current/fundamentals/crud/read-operations/retrieve/
Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

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.

Query is not working with promise for Dynamo DB

I have a dynamo db table where I was able to insert data using node js via lambda. I am able to query from the console and I am also able to query using the cli. When using query with promise its erroring out with invoke error. Its not throwing any specific errors. IF I remove promise and run I can see that connection is successful to the db. I also tried ExpressionAttributeValues: {
":name": {"S":id}
},
even hard coding the value for id and same issue. What am I doing wrong??
import AWS from "aws-sdk"
const dyanamoDB = new AWS.DynamoDB.DocumentClient()
AWS.config.update({ region: "us-east-1" })
export const checkIFIDExist = async (id) => {
try {
const params = {
ProjectionExpression: "String1, String2",
IndexName: "String2",
KeyConditionExpression: "String2 = :name",
ExpressionAttributeValues: {
":name": id
},
TableName: 'my-table',
}
const data = await dynamoDB.query(params).promise()
console.log("Data:", data)
return "success"
}catch (err) {
throw new Error (`Failed query for ${id} `, err)
}
}
Error:
2022-08-16T20:24:09.210Z c2e0c093-2719-48b8-b0bb-4f38de3ac7b6 ERROR Invoke Error
{
"errorType": "Error",
"errorMessage": "Failed query for OE0K0I ",
"stack": [
"Error: Failed query for OE0K0I ",
" at checkIFStepFunctionIDExists (file:///var/task/src/dynamo-query.js:24:15)",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)",
" at async Runtime.handler (file:///var/task/src/index.js:11:19)"
]
}
I basically deleted and trashed the project created new one and did the same stuff I had mentioned earlier in my post and instead of throwing error after catch statement console log it and I am getting the result I expected. I really couldn't tell what was I doing wrong before. #jarmond the error I posted above, I accidentally included a dependency while changing something and caused the error I provided. Thanks everyone for looking into the issue.
If the promise() function doesn't do what you expect it to do. It's worth noting, that you can actually also do the same thing with the standard Node.js promisify function.
import { DocumentClient } from "aws-sdk/clients/dynamodb";
import { promisify } from "util";
const docClient = new AWS.DynamoDB.DocumentClient()
...
const data = await promisify((cb) => docClient.query(params, cb))();
As #jarmod pointed out, there's probably something else going on though. I added some sidenotes to clarify some things that you may or may not already know.
Some sidenotes
Here are just some remarks which aren't entirely on topic but which can lead to confusion.
// don't do this, it doesn't do what you think it does.
throw new Error(`Failed query for ${id}`, err );
// this prints both a text and an object.
console.error(`Failed query for ${id}`, err);
// this throws just an error with a message
throw new Error(`Failed query for ${id}`);
// there is a 2nd argument which you can pass, which is an "options" parameter, which you can use to send a `cause` along.
throw new Error(`Failed query for ${id}`, { cause: err } );
PS:More details about it can be found it in the MDN documentation.
I haven't seen how you got it working without the promise, but if you did it like this, then it's not what you think.
try {
const params = { ... };
dynamoDB.query(params);
// this point is always reached
return "success"
}catch (err) {
// this point is never reached
}
Instead, without a promise, you would have to use a callback function.
const params = { ... };
dynamoDB.query(params, (err, data) => {
if(err) {
console.error(err);
return;
}
console.log("success", data);
});

How to handle errors using the Tedious driver with Node

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`);
}

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)
}
}

Resources