Not getting a response using Mongoose - javascript

I am creating a document in my MongoDB database using Mongoose with the following code:
workoutsRouter.post('/', async (req, res) => {
await mongoose.connect('mongodb+srv://nalanart:<password>#cluster0.2iplh.mongodb.net/workout-app-db?retryWrites=true&w=majority',
{ useNewUrlParser: true, useUnifiedTopology: true })
await Workout.create({
mains: req.body.mains,
accessories: req.body.accessories
}, err => {
if(err) {
throw err
} else {
res.sendStatus(201)
}
})
})
My problem is that it does not send a 201 status as I have written it to. Any idea why? It just says Sending... on Postman
And here it appears in my collection:

Yeah, because you are both awaiting and passing a callback. You are mixing the await and callback syntaxes. If you pass Mongoose a callback, it won't return a Promise, so it will be awaited forever, since it will never resolve. Either await it, or pass it a callback, not both. Also, try res.status(201).end()
try {
await Workout.create({
mains: req.body.mains,
accessories: req.body.accessories
});
res.status(201).end();
} catch (err) {
throw err
}

Related

Database Querying function not running asynchronously

So I created a function in my node server which takes in a query string, runs it on my db, and returns the results. I then wanted to use my function asynchronously using async await throughout my routes instead of having nested query within, nested query, within nested query etc.
So here is the code:
const runQuery = queryString => {
console.log("...runQuery")
db.query(queryString, (error, results, fields) => {
if (error) {
console.log("runQuery: FAILURE");
return error;
}
else {
console.log("runQuery: SUCCESS");
return(results);
}
})
}
register.post("/", async (req, res) => {
console.log(req.body);
const results = await runQuery("select * from test1");
res.send(results);
})
The database should have 3 entries, but unfortunately, it returns nothing. Meaning results is an empty variable when it is sent, meaning JS never properly waits for it to capture the db results. How can I use my function asynchronously, and how is this even feasible?
It seems your function "runQuery" does not return a promise, in fact, it's not returning anything. You are using "return" in the callback of the db.query function, not the function "runQuery" itself.
Since runQuery is performing an asynchronous operation, the result ought to be resolved via a promise (which is what the "await" in your request handler is looking for).
I'm not exactly sure but it seems you are using MySql, and I could not find anything on the npm page of the mysql package regarding the query being promisified, so we'll promisify it ourselves:
const runQuery = (queryString) => new Promise((resolve,reject) => {
console.log("...runQuery")
db.query(queryString, (error, results, fields) => {
if (error) {
console.error("runQuery: FAILURE");
reject(error);
} else {
console.log("runQuery: SUCCESS");
resolve(results);
}
})
})
register.post("/", async (req, res) => {
console.log(req.body);
try{
const results = await runQuery("select * from test1");
res.send(results);
}catch(e){
console.error(`ERROR THROWN BY runQuery:`,e);
res.status(500).send({
message: e.message || "INTERNAL SERVER ERROR"
})
}
})
Note that if an error occurs, our promisified function will reject the error and it will NOT be stored in the "results" variable in our request handler. Instead, an error will be thrown which needs to be handled. Therefore, it is always a good practice to put any async/await calls inside a try/catch.

Nodejs APi doesn't get result

i'm a beginner in Nodejs.
I'm trying to use async/ await to create an api:
getAllTasks: function (callback) {
return db.query("Select * from tasks", callback);
},
function asyncGetAllTask(){
return new Promise((resolve,reject)=>{
resolve (Task.getAllTasks());
})
}
router.get('/:id?', async function (req, res) {
if(req.params.id){
await asyncGetTaskByID(req)
.catch(err=>{
res.send(400, {status:400, message: 'bad request', type:'client errors'});
})
.then(rows=>{
res.json(rows)
})
}
else {
await asyncGetAllTask()
.catch(err=>{
res.json(err);
})
.then(rows=>{
res.json(rows);
})
}
});
I'm trying to get all "tasks" from the database (i'm using mysql). However, i don't get the tasks rows. Instead, i get this when i use a get method from postman:
{
"domain": null,
"_events": {},
"_eventsCount": 0,
"_callSite": {},
"_ended": false,
"_idleNext": null,
"_idlePrev": null,
"_idleStart": null,
"_idleTimeout": -1,
"_repeat": null,
"sql": "Select * from tasks",
"typeCast": true,
"nestTables": false,
"_resultSet": null,
"_results": [],
"_fields": [],
"_index": 0,
"_loadError": null
}
Am i missing some thing? I don't understand somehow i got the wrong result.
Sorry for my English.
Thank you
The combination of the await keyword, with the promise interface and handlers (ie .catch() and .then()) looks in correct here.
If you want to use await, you should restructure your code along the lines of this (note the use of try and catch, to achieve the catch-like behaviour that you want for error handling):
router.get('/:id?', async function (req, res) {
try {
if(req.params.id){
// Correct use of await typically does not require the use of .then()
// and is as follows
const rows = await asyncGetTaskByID(req)
res.json(rows)
}
else {
// Correct use of await typically does not require the use of .then()
// and is as follows
const rows = await asyncGetAllTask()
res.json(rows);
}
}
catch(err) { // Catch block to return error result
res.send(500, {status:500, message: 'an error occurred'});
}
});
Additionally, you will likely need to update your method asyncGetAllTask() to the following:
function asyncGetAllTask(){
return new Promise((resolve,reject)=>{
// The resolve callback should probably be passed to getAllTasks
// as per your defintion of Task.getAllTasks
Task.getAllTasks((error, rows) => {
if(error) {
reject(error);
} else {
resolve(rows);
}
});
})
}

get data with find in mongoose and node

I have a problem returning some data from a db in mongodb. I put you in situation.
I have a file called db.js, which has the following content:
const mongoose = require('mongoose');
var libro = mongoose.Schema({
titulo: String,
estado: String,
autor: String,
genero: String
});
module.exports = mongoose.model('estanteria', libro);
I have another file called estanteria.js that has the following content:
const Libreria = require('./db');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/libreria', (err) => {
if(err) throw err;
console.log("Conexión a db correcta");
});
...
function allBooks(){
var libros = Libreria.find({})
return libros;
}
exports.allBooks = allBooks;
The problem I have in the function allBooks(), I do not know how to return the contents of the collection in an array of objects, and then display it on the web. Can somebody help me?
Inside allBooks function add a callback function to return after find operation.
function allBooks(){
Libreria.find({}).exec(function(error, records) {
if (!error) {
res.send({
success : true,
records : records
});
} else {
console.log(error);
res.send({
success : false,
error : error
});
}
});
}
exports.allBooks = allBooks;
Use JSON.stringify() to encode libros in a jhson format then write it as an response to the request ( The request recieved by the server )
Libreria.find({}) is an async operation, you need to use Promises way to handle this. As shown below:
Libreria.find returns a promise and you can handle the resolve state of this promise in .then method and if any error occurs it will be done in .catch
function allBooks(){
Libreria.find({})
.then(function(books) {
return books;
})
.catch(function(error){
return error;
})
}
// An exmaple router handler as follow:
router.get("/posts", function(req, res){
allBooks()
.then(function(records){
res.json({status: true, records})
})
.catch(function(error){
res.json({status: false, error })
});
})
Read more about mongoose promises: http://mongoosejs.com/docs/promises.html
Promises in general: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

How can I catch errors here?

I have router and two acync fetching from DB. What is the correct way to catch errors here?
router.get('/restaurant/:id', async (req, res, next) => {
var current_restaurant = await Restaurant.findOne({restaurantId: req.params.id}).exec();
var products = await Product.find({restaurant: req.params.id}).exec();
res.render('restaurant', {
user: req.user,
csrfToken: req.csrfToken(),
current_restaurant: current_restaurant,
products: products
});
});
Either:
try {
var current_restaurant = await Restaurant.findOne({restaurantId: req.params.id}).exec();
var products = await Product.find({restaurant: req.params.id}).exec();
res.render('restaurant', {
user: req.user,
csrfToken: req.csrfToken(),
current_restaurant: current_restaurant,
products: products
});
} catch (err) {
// Handle your errors here...
}
which is your typical pattern. Depending on if you can recover and continue with the rendering (with a default value or something), you might want to enclose only the await calls in the try block (and declare the variables before the try block).
Otherwise, you're awaiting promises, so you can still use the promise .catch method if that seems cleaner to you.
var current_restaurant = await Restaurant.findOne({restaurantId: req.params.id}).exec()
.catch(err => { /* handle error here*/ });
var products = await Product.find({restaurant: req.params.id}).exec()
.catch(err => { /* handle error here*/ });
However, this pattern is only going to be useful if you can still return something valid in your catch code (eg, some kind of default or fallback value). If you need to bail out of the whole thing in the event of an error, this won't work for you, and you should use the previously mentioned try/catch pattern instead.
If you're going to use await, then you would use try/catch to catch a rejection of either of the promises you were awaiting:
router.get('/restaurant/:id', async (req, res, next) => {
try {
let current_restaurant = await Restaurant.findOne({restaurantId: req.params.id}).exec();
let products = await Product.find({restaurant: req.params.id}).exec();
res.render('restaurant', {
user: req.user,
csrfToken: req.csrfToken(),
current_restaurant: current_restaurant,
products: products
});
} catch(e) {
// do whatever you want
console.log(e);
res.sendStatus(500);
}
});
You can compare that to regular promise programming using .then():
router.get('/restaurant/:id', async (req, res, next) => {
Promise.all([
Restaurant.findOne({restaurantId: req.params.id}).exec(),
Product.find({restaurant: req.params.id}).exec()
]).then([current_restaurant, products] => {
res.render('restaurant', {
user: req.user,
csrfToken: req.csrfToken(),
current_restaurant: current_restaurant,
products: products
});
}).catch(e => {
// add your desired error handling here
console.log(e);
res.sendStatus(500);
});
});
Since your two database requests are independent of one another, the second version allows the DB queries to be parallelized and may actually run slightly faster (depends upon your database).

How to set default rejected promise behavior for all my Express middlewares?

I'm using promises inside express middleware. I want to use the async/await methods.
app.get('/data1',async function(req,res) {
data = await getData1(); // This line throw an error,
res.send(data)
})
app.get('/data2',async function(req,res) {
data = await getData2(); // This line throw an error
res.send(data)
})
This makes the browser wait forever.
On the server I see
(node:251960) UnhandledPromiseRejectionWarning: Unhandled promise rejection
Now, to fix it for one middleware I'm doing:
app.get('/data1',async function (req,res){
return (async function(){
data = await getData1()
})().catch(() => {
res.send("You have an error")
}
})
app.get('/data2',async function (req,res){
return (async function(){
data = await getData2()
})().catch(() => {
res.send("You have an error")
}
})
I don't like this repetion. How can I set default error? I have tried for example:
app.use(function(error,req,res,next)){
res.send('You have an error')
}
But it didn't work.
In other words: How to set default function to be called when Express middlewares returning a rejected promise?
Now I found a way how to do it, I'm still keep the question open for more suggestions
app.get("/data1",
wrap_middleware(async (req, res) => {
data1=await getData1()
res.send(data1)
})
}
app.get("/data1",
wrap_middleware(async (req, res) => {
data2=await getData2()
})
}
function wrap_middleware(func) {
return async (req, res, next) => {
func(req, res, next).catch(err => {
console.log(err.message);
res.send("Error");
});
};
}
I don't understand the use of sending the same error for different function but I think the handling error code could be write in more readable way (just catch the error and do with them what you want the same way you catch errors in any route middleware):
function getData1(){
return new Promise( (resolve,reject) => {
setTimeout(() =>{
reject(new Error('error has occur!'));
},2000);
});
}
router.get('/data1', async (req,res, next) => {
try{
const data = await getData1();
res.send(data);
}
catch(ex){
res.send(ex.message);
// next(ex); => sending it to express to handle it
}
});
If you want a global error handling then its not any different from any code you want catch errors globally - you can set a function that take as param , the response object and the async code and create general catch for every async call comes from middleware (which has response object)

Categories