I'm currently working on the freeCodeCamp Exercise Tracker Project on Replit.
my Project Link: https://replit.com/#mazorSharp/Exercise-Tracker?v=1
If you click on the link, the code I'm referring to is in the server.js file and It's the code under the comment labeled // NUMBER 3
I'm running into an issue with one of the GET routes.
GET user's exercise log: GET /api/users/:_id/logs?[from][&to][&limit]
The GET route works fine when all queries are used in the get search. Queries for the test are From, To, and Limit. If one of the queries aren't present in the GET request I get an error.
CastError: Cast to date failed for value "Invalid Date" (type Date) at path "date" for model "exerciseInfo"
What steps would I need to take to make sure if someone isn't putting in values for FROM, TO, and LIMIT queries that it wouldn't throw an error because of it?
app.get('/api/users/:_id/logs', (req, res) => {
const {from, to, limit} = req.query;
let idJson = {"id": req.params._id}
let idToCheck = idJson.id;
console.log("from=> ", from, "to=> ", to, "limit=> ", limit, "idToCheck=> ", idToCheck);
//Check ID
ExerciseInfo.findById(idToCheck, (err, data) => {
if (err) {
console.log("Error with ID => ", err);
} else {
// Find Username Documents
ExerciseInfo.find(({username: data.username}, {date: {$gte: new Date(from), $lte: new Date(to)}}), null , {limit: +limit} , (err, doc) => {
let loggedArray = []
if (err) {
console.log("error with username=> ", err);
} else {
console.log("all docs related to username=> ", doc);
let documents = doc;
let loggedArray = documents.map((item) => {
return {
"description": item.description,
"duration": item.duration,
"date": item.date.toDateString(),
}
})
const test = new LogInfo({
// "_id": idToCheck,
"username": data.username,
"from": from,
"to": to,
"count": limit,
"log": loggedArray,
})
test.save((err, data) => {
if (err) {
console.log(err);
} else {
console.log("saved exercise successfully")
res.json({
"_id": idToCheck,
"username": data.username,
"from": data.from.toDateString(),
"to": data.to.toDateString(),
"count": data.count,
"log": loggedArray,
})
}
})
}
})
}
})
})
Related
So guys i'm setting up my backend in NodeJS for an e-commerce website.
But I ran into an error trying to implement the "Order" method.
First the connection to mysql database :
let mysql = require('mysql')
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'ecom_new'
})
connection.connect()
module.exports = connection
Then in my Models there is a Client class that contains the following method :
static order(orderData, callbackfn) {
orderData.products.map((product) => {
connection.query(`INSERT INTO orders SET
product_name = ?, owner = ?, quantity = ?, price = ?, client_name = ?, client_phone = ?, client_address = ?`,
[product.name, product.owner, product.count,product.price, orderData.clientName,
orderData.clientPhone, orderData.clientLoc], (err, result) => {
if (err) {
callbackfn(err)
} else {
callbackfn(null, result)
}
})
})
}
The orderData parameter in the order() method is a JSON posted from the frontend, that looks like this:
{
"products": [
{"name": "Item 1", "owner": "Clint", "count": 1, "price": 150},
{"name": "Item 2", "owner": "Steve", "count": 3, "price": 350},
{"name": "Item 3", "owner": "Bruce", "count": 6, "price": 110}
],
"clientName": "Tony Stark",
"clientPhone": "111111",
"clientLoc": "Malibu"
}
And finally the route that handles this request is coded like this :
router.post('/client/order', (req, res) => {
Client.order(req.body, (err, result) => {
if (err) {
res.json({RequestResult: 'ERROR', Message: err['sqlMessage']})
} else {
res.json({RequestResult: 'SUCCESS', Message: 'New order placed successfully'})
}
})
})
It works just fine when I try (once) to place an order from my frontend (and Postman).
But the issue is that whenever I try (again) to place an order i'm getting the [ERR_HTTP_HEADERS_SENT] error. Looks like i can only place an order once, which is nonsense.
I don't really know what is wrong and it is keeping me from moving on to other concerns of my project, help is needed.
Thanks
I think the problem is that you iterate over the products with orderData.products.map((product) => {... and for each product you call the callbackfn which in turn calls res.json({...}). So for each product a res.json({...}) is called but i think you are only allowed to call it once per request.
Try something like this in the Client class:
static order(orderData) {
return Promise.all(orderData.products.map((product) => {
return new Promise((resolve, reject) => {
//run query
if (err) reject(err)
else resolve()
})
}))
}
now you can use this function like so:
Client.order(req.body)
.then(() => res.json({ RequestResult: 'SUCCESS', Message: 'New order placed successfully' }))
.catch(err => res.json({ RequestResult: 'ERROR', Message: err['sqlMessage'] }))
Why is a successful update response always passed as an error. is something wrong with my code or is it the Mongo DB response.
However I don't see any errors when I check them on MongoDB.
MongoDB Enterprise > db.getLastError();
null
Response:
{
"lastErrorObject": {
"n": 1,
"updatedExisting": true
},
"value": {
"_id": "1111111111",
"xyz": "hgfjdfjk"
}
}
Code Block
{
try {
const db = client.db(dbName);
db.collection(cName).updateOne({ _id: id }, { $pull: query }).then((err, result) => {
if (err) {
callBack(err);
} else {
callBack(null, result);
}
});
client.close();
}
catch (err) {
callBack({
error: 'Unable to process the request',
errorMessage: err
})
}
}
getLastError() returns the server response to the current operation within that connection, and is not related to an actual error in MongoDB. It is part of MongoDB's wire protocol.
See getLastError for more details.
I developped an invoice using ReactJS, nodejs and mysql, it have a dynamic table, as you can see the invoive component in this link : https://codeshare.io/5zqLeN
My router is :
exports.ajouterfact = function(req, res) {
console.log("req", req.body);
var today = new Date();
var factures = {
"Nfact": req.body.Nfact,
"Nom": req.body.Nom,
"Datefact": req.body.Datefact,
"Note": req.body.Note,
"Nomp": req.body.Nomp,
"QuantiteF": req.body.QuantiteF,
}
connection.query('INSERT INTO factures SET ?', factures, function(error, results, fields) {
if (error) {
console.log("error ocurred", error);
res.send({
"code": 400,
"failed": "error ocurred"
})
}
else {
// console.log('The solution is: ', results);
res.send({
"code": 200,
"success": "facture registered sucessfully"
});
}
})
};
My invoice is :
When I submit it, It will be added on the database by getting:
req { Nfact: '15',
Nom: 'Imen',
Datefact: '2018-09-04T09:47:32.925Z',
Note: 'Test',
QuantiteF: '' }
The Noun of product (Nomp) is null and the quantity is ''.
But when I run my backend with Postman, it works well.
How can I fix that ?
I'm using SailsJS as an API with Waterline connected to a MongoDB. I'm trying to put together an endpoint to edit existing DB entries but can't seem to get it to work and I'm hitting a wall as to why.
My route:
'post /edit/safety/:id': {
controller: 'SafetyController',
action: 'editSafety'
},
My controller function:
editSafety: function editSafety(req, res) {
var id = req.params.id;
Safety.findOneById(id).then((err, safety) => {
if (err) {
res.send(500, err);
return;
}
if (!safety) {
res.send(404, err);
return;
}
safety.title = req.body.title;
safety.description = req.body.description;
safety.status = req.body.status;
safety.save((err, updatedSafety) => {
if (err) {
re.send(500, err);
return;
}
res.send(200, updatedSafety);
});
});
},
Any push in the right direction would be greatly appreciated.
I don't recognize the Safety.findOneById method - is this something you have custom built? If not, then it is likely your problem.
Try swapping it for either:
Safety.findOne(id)
or
Safety.findOne({id: id})
Note that the returned object will be a model instance if the record exists, and undefined otherwise. If you decide to go with Safety.find instead then the returned value will be an array containing all models matching the query.
Looks like the main issue was transposing the response and err objects. It was successfully completing the query, but loading it into the err object which gets caught and a 500 error is thrown. So I changed that and simplified in a few other places.
editSafety: function editSafety(req, res) {
var id = req.params.id;
Safety.findOne(id).then((response, err) => {
var safety = response;
if (err) {
res.send(500, err);
return;
}
if (!response) {
res.send(404, err);
return;
}
safety.title = req.body.title;
safety.description = req.body.description;
safety.status = req.body.status;
Safety.update({
id: id
}, safety)
.then((result) => {
res.json(200, 'Ok!');
})
.catch((err) => {
sails.log.error('SafetyController.editSafety', err);
})
});
},
So I am trying to update the field status in my Report document and in my Station.reports sub-document which is an array of objects, in one single API call. The issue is that I am able to update the Report document, but not the station document when making the API call. After the call, the console.log(station.reports); returns the expected subdocument which is : [{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}] But this is not saved in the corresponding Station document in my DB. Please I need help here. Thanks.
Station Document:
{
"_id": "588a777d4e26720e7afa7e1e",
"phone": "(007) – 007 – 7007",
"name": "name1",
"email": "name1#email.com",
"reports": [
{
"status": "Submitted",
"date": "2014-01-31T01:48:57.487Z",
"_id": "588fed278b50cd180bd6cc15"
}
]
}
Report Document
{
"_id": "588fed278b50cd180bd6cc15",
"description": "Description of the report",
"time": "05:48 PM",
"date": "2017-01-31T01:48:57.487Z",
"status": "Archived",
"location" : "123 Main Street"
"station" : "588a777d4e26720e7afa7e1e"
}
API Call
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOne({_id:report.station}, function (err, data) {
if(err) return console.log(err);
data.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
rpt.status = req.body.status
data.save(function (err, station) {
if (err)
return res.send(err);
console.log(station.reports);
})
}
})
})
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
})
});
})
You are doing mistake while updating the station object. Use findOneAndUpdate to find the matching Station document, and then change the status of the matched reports item(matched using reports._id).
Try this:
Station.findOneAndUpdate({
_id:report.station,"reports._id":req.params.id
},{
$set : {reports.$.status : req.body.status}
},function(err){
if(err)
return res.send(err);
});
report._id will find the array element whose _id is req.params.id and report.$.status will update only the matching element of the array.
For more information on positional $(update) operator, Read mongoDB positional Documentation.
Also, i would suggest to save the report object in the callback of update. As nodejs is asynchronous, it will not wait for the update to finish, if you are saving report outside of the callback. And, you might get Cant set the headers after they are sent error. Thus, its recommended to do it in the callback.
Thus your final API code would look like:
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOneAndUpdate({
"_id":report.station,"reports._id":req.params.id
},{
$set : {"reports.$.status" : req.body.status}
},function(err, result){
if(err)
return res.send(err);
console.log(result);
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
});
});
});
})
UPDATE
Alternate Method
Another way can be, You can proceed in the original way, but don't save the data inside the forEach, instead save the data sheet forEach finishes.
Station.findOne({_id:report.station}, function (err, data) {
if(err) return console.log(err);
data.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
rpt.status = req.body.status
}
});
data.save(function (err, station) {
if (err)
return res.send(err);
console.log(station.reports);
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
});
})
})
Hope this helps!
After multiple attempts, and with the help of Ravi, I was able to figure out a solution that worked for me pretty well. The only thing that changed was my API call. The rest of the code was unchanged.
Hope this helps someone having similar needs.
API CALL
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOne({_id:report.station}, function (err, info) {
if(err) return console.log(err);
info.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
Station.update({_id:info._id, "reports._id":rpt._id },
{
$set:{"reports.$.status": req.body.status }
},function (err, results) {
if(err) return console.log("This Station couldn't be updated " + err);
console.log(results)
}
)
}
})
report.save(function (err, report) {
if (err)
return res.send(err);
res.json({report:report, station:info});
});
})
});
})