My mongoose model works fine with promises .then() and .catch. However, if I do await User.findOne({ email }), my response test in Postman infinitely awaits.
class UserController
{
...
static async RegisterUser(req, res)
{
...
const doesUserExist = await User.findOne({ email });
if(!doesUserExist)
{
return res.status(400).json({ message: 'User does not exist' });
}
...
}
}
Here is my DB connection if necessary:
const connectDB = async () => {
try {
console.log('Connecting to database...');
const admin = process.env.API_USN;
const adminPassword = process.env.API_PASS;
const options = {
useNewUrlParser: true,
useUnifiedTopology: true
};
const databaseURL = process.env.APP_DB_URL
.replace('<password>', adminPassword)
.replace('<admin>', admin)
.replace('<username>', admin)
console.log(`Connecting to: ${databaseURL}`)
const conn = await mongoose.connect(databaseURL, options);
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.log(error);
process.exit(1);
}
};
Anyone know why async/await infinitely waits but .then()/.catch() works perfectly fine? I even tried awaiting User.findOne().exec()
Related
When I go to test my code, the lambda does nothing, and at other times it runs my query and returns the data I have queried for. It's very inconsistent. It doesn't even give me an error. I am also using a proxy and that's not showing any errors. That's also not triggering.
I suspect it's something to do with the await/ async...
Here is my code:
async function RDSToken() {
vr signer = new AWS.RDS.Signer({
region: 'us-east-1',
hostname: 'proxy',
port: 3306,
username: 'username'
});
var host ='proxy'
var user ='username'
var db ='name'
let token = signer.getAuthToken({username: 'admin' });
let connectionConfig = {
host: host,
user: user,
database: db,
ssl: { rejectUnauthorized: false},
password: token,
authSwitchHandler: function ({pluginName, pluginData}, cb) {
console.log("Setting new auth handler.");
}
};
connectionConfig.authSwitchHandler = (data, cb) => {
if (data.pluginName === 'mysql_clear_password') {
let password = token + '\0';
let buffer = Buffer.from(password);
cb(null, password);
}};
try {
connection = await mysql2.createConnection(connectionConfig);
} catch(err) {
console.error('error connecting to the database');
console.error(err);
var response = {
statusCode: 500,
"headers": {
"Content-Type": "application/json"
},
body: 'error connecting to the database' +err
};
return response;
}
return connection
}
async function randomfact() {
var connection = await RDSToken();
let sql = 'SELECT * FROM quote_header;';
return await new Promise((resolve, reject) => {
connection.query(sql, (err, result) => {
if (err) {
reject(err);
}
else {
resolve(result);
}
});
});
}
async function Dashboard() {
const result = await randomfact();
console.log(result)
}
So I was correct there is something to do await/asnyc/promise.
Here is my updated code.
const connection = mysql2.createPool({
host: "host",
user: "admin",
password: "pw",
database : 'name',
waitForConnections: true,
connectionLimit: 3,
})
SelectAllElements = (connection) =>{
return new Promise((resolve, reject)=>{
connection.query('SELECT * FROM quote_header ', (error, elements)=>{
if(error){
return reject(error);
}
return resolve(elements);
});
});
};
async function Dashboard() {
try{
const result1 = await SelectAllElements(connection);
console.log(result1)
// here you can do something with the three results
} catch(error){
console.log(error)
}
}
But this works around 95% of the time. It doesn't like to work the first time I run the lambda but after then it works for a short time, then returns null again, then works again. I still dont understand what's causing it not to connect.
I'm trying to call my global variables in my controller but i got an error variable is not defined. Please see the code below for your reference. Hoping to solve my problem. Thank you Guys
**server.js **
const serverConfig = require('./config/server.config')
const app = require('fastify')({ logger: true })
require('./models/response.model')
const mongoose = require('mongoose')
const conn = require('./config/monggo.config')
require('./routes/dbm.routes')(app)
const connect = async () => {
try {
await mongoose.connect(conn.uri)
console.log('Connected to Mongoose!')
} catch (error) {
console.log(error)
}
}
connect();
app.listen(serverConfig.port, '::', (err, address) => {
if (err) {
app.log.error(err)
process.exit(1)
}
console.log('Listening at', address)
})
response.model.js
module.exports = function () {
global.successModel = {
status: 'sucess',
statusCode: 0,
isSuccess: true,
message: ''
}
global.failModel = {
status: 'failed',
statusCode: 1,
isSuccess: false,
message: 'Error encountered while processing request.'
}
}
**monggo.controller.js
**
exports.getProducts = async (req, res) => {
//find Products in the databse
Product.find({}, (err, product) => {
//send error message if not found
if (err) {
res.send(err);
}
//else pass the Products
res.send(successModel);
})
await res;
}
Hoping to solve my problem. Thank you
The './models/response.model' file exports a function that you need to call to "install" your globals.
- require('./models/response.model')
+ require('./models/response.model')()
As a suggestion, you should avoid to use globals, in fastify you can use:
decorator to add to your app instance useful data such as configs
Moreover, your mongoose connection is unrelated with Fastify, you can encapsulate it into a plugin to be sure that fastify is starting after connecting to the database:
const fp = require('fastify-plugin')
app.register(fp(async function connect (instance, opts) {
await mongoose.connect(conn.uri)
}))
I am trying to get a count of products using api calls but in postman its keep loading
router.get(`/get/count`, async (req, res) => {
const productCount = await Product.countDocuments((count)=>count)
if (!productCount) {
res.status(500).json({ success: false });
}
res.send({
productCount: productCount
});
});
(node:28030) UnhandledPromiseRejectionWarning: MongooseError: Query was already executed: Product.countDocuments({})
without async and await also its not working
I try to catch the error and i got this error in postman
{
"success": false,
"error": "Query was already executed: Product.countDocuments({})"
}
code to catch error:
router.get(`/get/count`, (req, res) => {
Product.countDocuments((count)=>count).then((pcount)=>{
if(pcount){
return res.status(200).json({success:true})
}else{
return res.status(404).json({success:false})
}
}).catch((err)=>{
return res.status(400).json({success:false, error:err.message})
})
});
I think in Mongoose operations you want to either await or provide a callback, but not both. Attempting to do both causes it to internally execute the query twice.
Try just:
const productCount = await Product.countDocuments();
If you want to count all the products in your product collection, try this
db.product.countDocuments({})
router.get(`/get/count`, async(req, res) => {
let productCount = await Product.countDocuments();
if(!productCount){
res.send(500).json({success:false})
}
res.send({productCount: productCount})
});
Two way you can do that
Try it you don't need use callback (count)=>count
const express = require('express')
const router = express.Router();
const {Product} = require('../models/products')
const {Category} = require('../models/category')
const catchAsyncErrors = require('../middleware/catchAsyncError')
const mongoose = require('mongoose');
// Get all product
router.get(`/`, async (req, res) => {
let productList = await Product.find().populate('category')
if(!productList) {
res.status(500).json({
success: false
})
}
res.status(200).json({
success: true,
count: productList.length,
productList
});
})
router.get(`/count`, catchAsyncErrors(async(req, res) => {
const countProductList = await Product.countDocuments();
if(!countProductList){
res.status(500).json({
success: false
})
}
res.send({
success: true,
countProduct: countProductList
})
}))
You don't need to include ((count)=>count).
Use Product.countDocuments() instead
I have initialized the connection to my mongodb and now export the db to other nodejs files. How can I do that?
i thought of something like this but it is giving errors.
let database;
export const connectDB = async () => {
const client = new MongoClient(config.dbUri, {
useUnifiedTopology: true,
});
try {
await client.connect();
database = client.db('azkaben');
logger.info('Connected to Database');
} catch (e) {
logger.error(e);
} finally {
await client.close();
}
};
export default database
Error : undefined value of database
database will always be null when you import it.
connectDB is aync call by the time it executes your database variable is already loaded as null.
connectDB you can return database from here.
export const connectDB = async () => {
const client = new MongoClient(config.dbUri, {
useUnifiedTopology: true,
});
try {
await client.connect();
database = client.db('azkaben');
return database; // you can get from here
logger.info('Connected to Database');
} catch (e) {
logger.error(e);
} finally {
await client.close();
}
};
Updated code
export const connectDB = async () => {
if (database) return database; // return if database already connected.
const client = new MongoClient(config.dbUri, {
useUnifiedTopology: true,
});
try {
await client.connect();
database = client.db('azkaben');
return database; // you can get from here
logger.info('Connected to Database');
} catch (e) {
logger.error(e);
} finally {
await client.close();
}
};
exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec()
if (user) {
return res.status(400).json({
errorMessage: 'Phone Number already exists',
});
}
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
**I upload a node application in shared hosting! **
*But an error was showing in this controller function. All the time the catch block is running on the json. The error is unhandled promise rejection. *
signup(data)
.then((response) => {
console.log('Axios signup success: ', response);
setFormData({
phone: '',
password: '',
password2: '',
loading: false,
successMsg: response.data.successMessage,
});
history.push('/signin');
})
.catch((err) => {
console.log('Axios signup error: ', err);
setFormData({
...formData,
loading: false,
errorMsg: err.response.data.errorMessage,
});
});
this is react front end event handler
import axios from 'axios';
export const signup = async (data) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const response = await axios.post('/api/auth/signup', data, config);
return response;
};
the signup api function
Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function. for example:
const query = Band.findOne({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));
// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (doc) {
// use doc
});
// `.exec()` gives you a fully-fledged promise
const promise = query.exec();
assert.ok(promise instanceof Promise);
promise.then(function (doc) {
// use doc
});
If you are using exec() on your findOne query you should use:
exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec();
/// just a pseudo code
user.then('do your things').catch( 'log error')
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
for more details check this out: https://mongoosejs.com/docs/promises.html#should-you-use-exec-with-await?