I wrote a small Javascript module to get rows from a MongoDB database:
async function getAll() {
await mongoose.connect(config.mongoURL).catch(err => { console.log(err); });
const conn = mongoose.connection;
conn.collection('healthdata')
.find({}).toArray().then(result => {
console.log('=>Docs:', result);
return result;
}).catch (err => {
console.log(err);
}).finally(() => {
conn.close();
});
}
exports.getAll = getAll
I get the correct display from the console ("=>Docs:").
But, when I want to get the result from the following calling function, I get the Undefined value ("Result:"):
app.get("/", async (req, res) => {
var docs = await db.getAll().then();
console.log("Result:", docs);
res.render("index.html");
});
What is missing? Wrong?
you should not mix promises with async/await, so either the answer provide by G-Force but remove the await before db.getAll() or use var docs = await db.getAll(); this should solve your problem.
Bro if you are using mongoose follow these to get data from mongoose schema
schema.find().exec().then(result=>{
console.log(result)
}).catch(error=>{
console.log(error)
})
here all schema data in result that we console if any error come it displays in console.log(error)
I think the console.log(Result:...) line is executing before your getAll completes.
I would wrap it inside the "then" clause:
app.get("/", async (req, res) => {
const docsReturned = await db.getAll()
.then(docs => {
console.log("Result:", docs);
res.render("index.html");
})
.catch(err => {
console.error(err);
}));
return(docsReturned);
I also suggest adding a catch for any errors...good practices. :)
Related
I am not much experienced with async/await, but I have incorporated the keywords in a function which basically fetch or POST data to MongoDB database. It seems like await does not wait for the promise to be fulfilled and returns an undefined response object.
I am getting the following error:
res.error(404).json({message: e.message})
^
TypeError: Cannot read properties of undefined (reading 'error')
at Object.getAllItems (/Users/myName/Desktop/TODOList/backend/Controllers/ItemsConroller.js:12:13)
Here is my code:
ItemsController.js:
const getAllItems = async (req, res) => {
try{
const items = await Item.find({})
res.status(200).json(items)
}
catch(e){
res.error(404).json({message: e.message})
}
}
Server.js file:
app.get('/todos', (req, res) => {
dbItem.getAllItems().then(data => {
console.log("entered")
res.send(data);
})
})
Same problem with other functions in the controller file which incorporates await/async keywords.
Thanks.
You are not passing your req and res object to your /todos endpoint:
To make you app more robust try this:
You can use getAllItems as your middleware like this
app.get('/todos', dbItem.getAllItems, (req, res) => {
if(!req.error){
res.send(req.items)
}else{
res.send(req.error)
}
})
And attach your variables to the req object and pass them to /todos
const getAllItems = async (req, res, next) => {
try{
const items = await Item.find({})
req.items = items
next()
}
catch(e){
req.error = e.message
next()
}
}
The following code is anAPI endpoint taking a URL of an image as input, and outputing the URL of the newly created thumbnail.
I am trying the refactor the try/catch, to a .then().catch(), as I intend to had more then()s, to upload the newly created thumbnail to AWS s3 for instance).
const express = require("express");
const jimp = require('jimp');
const { v1: uuidv1 } = require('uuid');
const router = express.Router();
// GET all data from watchlist
router.post("/", async (req, res) => {
const url = req.body.url;
const tempPath = './public/uploads/';
const tempFileName = uuidv1();
const tempURL = tempPath + tempFileName;
const cleanedUrl = tempURL.slice(2, tempURL.length);
try {
jimp.read(url, (err, img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL)
})
res.status(201).json({ thumbUrl: `http://localhost:5000/${cleanedUrl}` });
} catch (err) {
res.status(400).json({
error: `${err})`,
});
}
});
module.exports = router;
The code I had in mind to remplace the Try/Catch, seems not to be working, as when using it, the API freezes and deliver no response (and no errors!?).
jimp.read(url, (err, img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL)
})
.then(() => {
res.status(400).json({
thumbUrl: `http://localhost:5000/${cleanedUrl}`,
});
})
.catch((err) => {
res.status(400).json({ error: `${err}` })
})
If someone could point me the error (or some good ressources for dummy about how to use then/catch, I can't find any I understand online) I will be highly grateful!
The Promise based version of .read does not accept a callback, so the code in the callback is getting ignored. You also have a typo - the status(400) in the Promise-based version in the .then should be .status(201). Change to:
jimp.read(url)
.then((img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL);
res.status(201).json({
thumbUrl: `http://localhost:5000/${cleanedUrl}`,
});
})
.catch((err) => {
res.status(400).json({ error: `${err}` })
})
As a side note, whenever you're using Node-style callbacks, identify errors by checking the first error parameter - in your original code, you're ignoring it (and the surrounding try/catch isn't accomplishing anything). For example:
jimp.read(url, (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
res.status(201).json({ thumbUrl: `http://localhost:5000/${cleanedUrl}` });
});
I am trying to make a request to the database (mongoDB) and save its return in a list of objects but the list is not getting filled. Here is the code
router.get('/all/:studentEmail', auth, async (req, res) => {
try {
const student = await Student.findOne({ email: req.params.studentEmail });
if (!student) {
return res.status(404).json({ msg: 'Student not found' });
}
var list = [];
student.exercises.map(async (exercise) => {
list.unshift(await Exercise.findById(exercise));
});
res.json(list);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
});
The database query await Exercise.findById(exercise) returns correctly the object, but res.json(list); returns empty. Do anyone know how to solve it?
The base issue is that res.json() executes way before student.exercises.map(async (exercise) => { completes. Putting await into map doesn't wait for each and every item in the async loop to process. Either use something like Promise.all() or use a for loop (other strategies can be used also). Decide which to use based on whether you can process in parallel or need to process in series. Try the following using Promise.all to execute async requests parallel using then on each Promise to execute an operation against list:
router.get("/all/:studentEmail", auth, async (req, res) => {
try {
const student = await Student.findOne({ email: req.params.studentEmail });
if (!student) {
return res.status(404).json({ msg: "Student not found" });
}
var list = [];
await Promise.all(
student.exercises.map((exercise) =>
Exercise.findById(exercise).then((result) => list.unshift(result))
)
);
res.json(list);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
Also, an alternative to unshift and just return the results if they are not nested, if they are nested you can consider flat():
const list = await Promise.all(
student.exercises.map((exercise) => Exercise.findById(exercise))
);
return res.json(list);
Hopefully that helps!
I made an api like below.
I think it works asyncrously well without doubt.
exports.query = async(req, res) => {
try{
const result = await user.findOne({})
res.send(result);
} catch(error) {
res.send(error)
}
}
But when I try this like below, I am not sure it works asyncrously or not.
exports.query = async(req, res) => {
try{
user.findOne({})
.then(async(result) =>{
order.findOne({id: result.id})
.catch(e => res.send(e)
} catch(error) {
res.send(error)
}
}
I have to attach 'await' in front of user.findOne({}) like below?
exports.query = async(req, res) => {
try{
await user.findOne({})
.then(async(result) =>{
Or it doesn't matter? That is, it works same asycrously, even though I don't write await in front to user.findOne using 'then'?
thank you so much for reading.
Generally, inside a single block, you should either use await, or use .then, but not both - similarly, using Promise.prototype.catch is really weird in combination with try/catch where you can already await.
For your exports.query to resolve once the second findOne finishes, await or return both Promises, and connect the inner findOne connected to the outer Promise chain. Consider something like this instead:
exports.query = async (req, res) => {
try {
const userResult = await user.findOne({});
const orderResult = await userResult.findOne({ id: userResult.id });
// do something with orderResult
} catch (error) {
res.send(error)
}
}
If you use .then and catch without await, then it would look like:
exports.query = (req, res) => {
return user.findOne({})
.then((result) => {
return order.findOne({
id: result.id
})
.then((orderResult) => {
// do something with orderResult
})
.catch(e => res.send(e))
});
}
With the code in the second snippet in your question, your try/catch block will never do anything useful, because any problem will trigger the .catch method, and because the Promise isn't being awaited. Better not to mix the two styles - either pick await and try/catchor .then and .catch, but not both, else the control flow may become difficult to make sense of.
First of all, async-await can be used in functions which returns a promise.
Why we have to use await instead of then. await process the code asynchronously by making the execution feel like synchronous.
In your first example, everything works fine as expected. But in the second one, you need to await the findOne query. Here the fineOne will work asynchronously
exports.query = async(req, res) => {
try{
user.findOne({})
.then(async(result) =>{
let orderResult = await order.findOne({id: result.id})
.catch(e => res.send(e)
} catch(error) {
res.send(error)
}
}
which can be again simplified to
exports.query = async(req, res) => {
try{
let result = await user.findOne({});
let orderResult = order.findOne({id: result.id});
} catch(error) {
res.send(error)
}
}
I am trying to request JSON data and import it into a certain part of my website. When I console log it I have no issues. However when I attempt to assign the data to a array and variable it says "TypeError: response.data.map is not a function"
the code right below works in console.
router.get("/", (req, res, next)=>{
axios.get("http://ddragon.leagueoflegends.com/cdn/6.24.1/data/en_US/champion.json")
.then(res => console.log(res))
.catch((err)=>{
console.log(err);
});
res.render("champions");
});
Once I add the array it no longer works
router.get("/", (req, res, next)=>{
axios.get("http://ddragon.leagueoflegends.com/cdn/6.24.1/data/en_US/champion.json")
.then( (response)=>{
let championArray = [];
response.data.map((champs)=>{
championArray.push(champs);
});
res.render("champions", {
champs: championArray
});
})
.catch((err)=>{
console.log(err);
});
});
Once I assign the array it no longer works. I am trying to get this script to assign each champion to a variable so I can call it from the front end.
Since the API is returning array as objects, .map will not work. Try below code, it will work.
Object.keys(response.data).map((champs)=>{
championArray.push(champs);
});
router.get("/", (req, res, next)=>{
axios.get("http://ddragon.leagueoflegends.com/cdn/6.24.1/data/en_US/champion.json")
.then( (response)=>{
responseData = JSON.parse(response.data); //or just response idk :)
let championArray = [];
responseData.map((champs)=>{
championArray.push(champs);
});
res.render("champions", {
champs: championArray
});
})
.catch((err)=>{
console.log(err);
});
});
Try using the JSON.parse to create a JavaScript object out of the JSON response, note that this will only work if the request you make has a Content-type: application/json, otherwise try JSON.stringify. but the .map function is usually used on arrays not objects
Let me know if that helped
router.get("/", (req, res, next)=>{
axios.get("http://ddragon.leagueoflegends.com/cdn/6.24.1/data/en_US/champion.json")
.then( (response)=>{
let championArray = [];
let resData = response.data;
if (!resData.length){
resData.map((data, index) => {
if (!data){
data = JSON.parse(data);
championArray.push(data);
}
})
}
res.render("champions", {
champs: championArray
});
})
.catch((err)=>{
console.log(err);
});
});
The API response is an object. But .map is a function on arrays, which is why you are getting the error response.data.map is not a function.
Following are an option for you.
If you're using ES5,
Object.keys(response.data).forEach(function(key) {
console.log(key, response.data[key]);
});
using ES6, you could use for loop
for (const key of Object.keys(response.data)) {
console.log(key, response.data[key]);
}
in both cases, key would be the object key (in your case, the names) and response.data[key] would give you the data for that key.
Also note that since you're only interested in the values and not keys, you could simply use
Object.values(response.data)
Your final code would look like
router.get("/", (req, res, next)=>{
axios.get("http://ddragon.leagueoflegends.com/cdn/6.24.1/data/en_US/champion.json")
.then( (response)=>{
res.render("champions", {
champs: Object.values(response.data)
});
})
.catch((err)=>{
console.log(err);
});
});