For fetching a students applied programs - javascript

I am trying to fetch all the programs for the current applicant who is logged in and has applied for their bachelor's degree and store the fetched programs object id in an array.
I have tried the following but I'm not sure if it will work at first. Secondly, it will be quite helpful if you let me know what should I do to make it possible. I have shared the code I wrote. It is a MERN stack project and the backend is purely javascript.
Let me know if you can help me with the code below:
// #route GET /api/programs/applied-programs
// #desc Get all applied programs
// #access Private
router.get('/applied-programs', auth, async (req, res) => {
try {
const applicant = await Applicant.findOne({ user: req.user.id })
.select('-password')
.populate('user', ['email']);
let res = [];
const appliedPrograms = applicant.appliedPrograms.forEach(program => {
if (program) {
res = [program.id];
}
return res;
});
res.json(appliedPrograms);
} catch (err) {
console.log(err.message);
return res.status(500).send('Server Error');
}
});

So I just solved it myself. Just remembered that .forEach() function you have to pass an object the condition I was using was putting a check on the programs and I was passing the ids inside the array itself. Which surely is the wrong way to do it. So for now by using the .map() and mapping through the list of object and fetching their ids I just got what I wanted.
This is the proper way of doing so.
// #route GET /api/programs/applied-programs
// #desc Get all applied programs
// #access Private
router.get('/applied-programs/:id', auth, async (req, res) => {
try {
const applicant = await Applicant.findOne({ user: req.user.id })
.select('-password')
.populate('user', ['email']);
let response = [];
const appliedPrograms = applicant.appliedPrograms.map(
program => program.id
// if (program) {
// response = [program.id];
// }
// return response;
// }
);
response = appliedPrograms;
res.json(response);
} catch (err) {
console.log(err.message);
return res.status(500).send('Server Error');
}
});

Related

How to wait for a variable to be populated by an api request before passing it to a webpage as an argument?

I'm new to JavaScript and cannot seem to make this work , the topic of quiz depends on the user input... when the user presses next , I get the topic (this also takes user to the main quiz page), then i have to fetch data from the api with the topic as a parameter... I have to process the result of the fetch operation.. Then I have to pass that info to to the main quiz page... but the variable that is supposed to be populated by the fetch request is still undefined when i pass is to the main quiz page
var Allquestions;
var sheetdb = require('sheetdb-node');
// create a config file
var config = {
address: 'https://sheetdb.io/api/v1/9djmf8ydc7hwy',
};
//sheetdb
// Create new client
var client = sheetdb(config);
function downloadquestions(topic) {
console.log(topic);
client.read({ limit: 2, sheet: topic }).then(function(data) {
console.log(data + " in client.read func")
processQuestions(data);
}, function(err){
console.log(err);
});
}
async function processQuestions(data) {
console.log(data + "data in process");
Allquestions = JSON.parse(data);
console.log(Allquestions[0].Question + " This is defined");
}
app.get("/", (req, res) => {
res.render("pages/index", { title: "Home"});
});
// app.post("/" , urlencodedParser ,(req , res) => {
// console.log(req.body.topic);
// })
app.get("/questions", urlencodedParser , (req , res) => {
downloadquestions(req.body.topic);
console.log(Allquestions + " this is undefined");
res.render("/pages/quizpage" , {Allquestions})
})
There are a few issues with your code, you have a broken promise chain, client.read( is a promise, and that promise is going nowhere. You either return it, or await it. To be able to await your will need to also mark your route (req, res) as async too.
Your code is a little mixed up, you have Allquestions as a global var, this isn't great for multi-user, as the last topic is going to override this each time.
Also try and avoid swallowing exceptions in utility functions, try and keep your exception handling at the top level, eg. in your case inside your req/res handler.
So with all this in mind, your refactored code could look something like ->
const sheetdb = require('sheetdb-node');
// create a config file
const config = {
address: 'https://sheetdb.io/api/v1/9djmf8ydc7hwy',
};
//sheetdb
// Create new client
const client = sheetdb(config);
async function downloadquestions(topic) {
const data = await client.read({ limit: 2, sheet: topic });
return processQuestions(data);
}
function processQuestions(data) {
return JSON.parse(data);
}
app.get("/", (req, res) => {
res.render("pages/index", { title: "Home"});
});
app.get("/questions", urlencodedParser , async (req , res) => {
try {
const allQuestions = await downloadquestions(req.body.topic);
res.render("/pages/quizpage" , {Allquestions});
} catch (e) {
console.error(e);
res.end('There was an error');
}
})

I want to know how to got COUNT from SQL in reactjs

my request is good but i want to know how can i use my response in React.
SQL request :
```
exports.countAllComments = async (req, res) => {
const pId = req.params.id;
db.query(
"SELECT COUNT(*) FROM comments WHERE post_id = ?",
[pId],
(err, count) => {
if (err) {
res.status(500).json({ err });
console.log(err);
} else {
console.log(count)
res.status(200).json(count);
}
}
);
};
```
Front for fetch count:
```
const [countData, setCountData] = useState(0);
useEffect(() => {
const fetchCount = async () => {
try {
const fetchData = await Axios.get(
`http://localhost:3001/api/post/comment-count/${post.id}`,
{
headers: { Authorization: `Bearer ${test1.token}` },
}
);
setCountData(fetchData.data[0]);
} catch (err) {}
};
fetchCount();
}, [post.id, test1.token]);
console.log(countData);
```
console log return : "{COUNT(*): 4}" how can i get (4)
given your trivial example, the trivial solution would be something like -
fetchData.data[0]['COUNT(*)']
however, you should really have a think about the contract on the API, and enforce a certain return type from your API, and not just simply return the response from the SQL query. i.e. your API could possibly return an object like -
{ count: x }
where its up to your API to transform the result from the SQL query in a way that satisfies the contract, that way your React client is disconnected from your database layer and only cares about your API contract.
That way your client side becomes something like -
fetchData.data.count
which wouldn't break if the query where to be updated in some way etc.

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client ASYNC AWAIT not Working

I am trying to verify if some data is in the session. If not the controller will redirect you to another route, to get that data.
The problem is that I am getting an error "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
I search over StackOverflow and I find that everyone that had this problem fix it using it async/await, but i was already using async await.
Your help will be trully appreciated!
Thank you very much!
Jose
dashboardCtrl.init = async (req, res) => {
//
var frontdata = req.session;
if (!frontdata.user) {
frontdata.user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
};
if (!frontdata.store) {
tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) {
res.redirect('/toURL');
};
};
};
Note: I am using EJS MATE.
If i do this
dashboardCtrl.init = async (req, res) => {
//
res.redirect('/toURL');
};
Redirect works, the problem is using await. So i dont know how to continue
That error says that you have already sent an answer to the cliente. In other words, you are trying to declare for the second time -> **res.*****.
Check the flow again in case you have twice declared any action on express's "res".
The solution below allows you to have a good structured and readable asynchronous code.
dashboardCtrl.init = (req, res) => {
// I think destructuring looks good
let { user, store } = req.session;
(async () => {
try {
if (!user) user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
let tmpstoredata;
if (!store) tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) res.redirect('/toURL');
} catch (err) {
// don't forget ;)
}
})()
};
Hope this can help you.
Greetings.
The code was OK
The problem was the EJS MATE
I replace it with EJS

Node.js. Filtering through a collection of referenced objects

I'm having issues filtering through an array of ObjectId's, which are a reference to another model. And to return an error if one or more with that ObjectId already exists within the array.
This is what the model looks like in the database
And this is my code
// #route PUT api/profile/favorites/:id
// #desc Add recipe to favorites
// #access Private
router.put('/favorites/:id', auth, async (req, res) => {
const post = await Post.findById(req.params.id);
try {
const profile = await Profile.findOne({ user: req.user.id });
const newFav = {
_id: post._id,
by: post.name,
nameOfDish: post.nameOfDish
};
console.log(profile.favorites.valueOf());
// Check if the post has already been added to favorites
if (profile.favorites.filter((favs) => favs.valueOf().toString() === post._id).length > 0) {
return res.status(400).json({ msg: 'Post already been favorited' });
}
profile.favorites.unshift(newFav);
await profile.save();
res.json(newFav);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
}); ```
Your code should still work. Are you sure the value and type of fav.valueOf().toString() and post._id are the same?
On a different note, why not use .find() method? It'll make the code easier to read.
Replace
profile.favorites.filter((favs) => favs.valueOf().toString() === post._id).length > 0
with
profile.favorites.find(fav => fav.valueOf().toString() === post._id)

how to break logic into a controller and a model in a node

I do not quite understand how to properly break the logic on the controllers and models in nodeJS when working with the backend application. Suppose I have an example
This code is in the model of my application, and logically I understand that the model is only responsible for choosing from the database, and the controller and everything else should be done by the controller, but I don’t quite understand how to do this and I tried to transfer part of the code to the controller and export it, but I did not succeed (Please, help, at least with this example! The main thing for me is to understand the principle of working with MVC in the node !!!
exports.currentPostPage = function(req, res){
db.query('SELECT * FROM `posts`', function (err, result) {
if (err){
console.log(err);
}
var post = result.filter(item => {return (item.id == req.params.id)? item: false})[0];
if (post === undefined){
res.render('pages/404');
} else {
res.render('pages/post-page', {postId: req.params.id, item: post});
}
});
};
So, you're on the right track. There's a lot of different ways to do it depending on preferences, but one pattern I've seen pretty commonly is to use the callback as a way to integrate. For example, let's say you have your model file:
exports.getPostById = (id, cb) => {
db.query('SELECT * FROM `posts` WHERE id=?', [id], function (err, result) {
if (err){
return cb(err); // or, alternatively, wrap this error in a custom error
}
// here, your logic is just returning whatever was returned
return cb(null, result);
});
};
Note I also am letting the DB handling the ID lookup, as it's probably more efficient at doing so for larger data sets. You didn't say what DB module you're using, but all the good ones have some way of doing parametrized queries, so use whatever works w/ your DB driver.
Anyway, the Model file therefore handles just the data interaction, the controller then handles the web interaction:
// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = (req, res, next, id) => {
model.getPostById(id, (err, post) => {
if (err) return next(err); // centralized error handler
req.post = post;
next();
});
}
export.getOnePost = (req, res, next) => {
if (req.post) {
return res.render('pages/post-page', req.post);
}
// again, central error handling
return next({ status: 404, message: 'Post not found' });
}
I have mentioned central error handling; I vastly prefer it to scattering error handling logic all over the place. So I either make custom errors to represent stuff, or just do like above where I attach the status and message to an anonymous object. Either will work for our purposes. Then, in a middleware file you can have one or more handler, the simplest like this:
// middleware/errors.js
module.exports = (err, req, res, next) => {
console.error(err); // log it
if (err.status) {
return res.status(err.status).render(`errors/${err.status}`, err.message);
}
return res.status(500).render('errors/500', err.message);
}
Finally, in your routing setup you can do things like this:
const postController = require('../controllers/postController');
const errorHandler = require('../middleware/errors.js');
const postRouter = express.Router();
postRouter.param('postId', postController.populatePost);
postRouter.get('/:postId', postController.getOnePost);
// other methods and routes
app.use('/posts', postRouter)
// later
app.use(errorHandler);
As was pointed out in the comments, some folks prefer using the Promise syntax to callbacks. I don't personally find them that much cleaner, unless you also use the async/await syntax. As an example, if your db library supports promises, you can change the model code to look like so:
exports.getPostById = async (id, cb) => {
// again, this assumes db.query returns a Promise
return await db.query('SELECT * FROM `posts` WHERE id=?', [id]);
}
Then your controller code would likewise need to change to handle that as well:
// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = async (req, res, next, id) => {
try {
const post = await model.getPostById(id)
req.post = post
return next()
} catch (err) {
return next(err)
}
}

Categories

Resources