Exercise tracker: problem with a test

Tell us what’s happening:
I am trying to pass the following test:

You can POST to /api/users/:_id/exercises with form data description , duration , and optionally date . If no date is supplied, the current date will be used. The response returned will be the user object with the exercise fields added.

And I’ve come up with the following code:

let schema = new mongoose.Schema({
  username: String,
  descritpion: String,
  duration: Number,
  date:Date
})
let Users = mongoose.model("Users", schema)
let newSchema = new mongoose.Schema({
  userId:String,
  description:String,
  duration:Number,
  date: Date
})
let Exercise = mongoose.model("Exercise", newSchema)
app.post("/api/users", (req,res) => {
  let user = new Users({
    username: req.body.username
  })
  user.save((err,data) => {
    if(err) return console.log(err)
    console.log("User saved successfully")
  })

  res.json(user)
})
app.get("/api/users", (req,res) => {
 Users.find({username: /\w/},(err,data) => {
   if(err) return console.log(err)
    res.json(data)
 })
})
app.post("/api/users/:id/exercises", (req,res) => {

 const userId = req.params.id

let {description,duration,date} = req.body
if(!date) {
  date = new Date()
}
 Users.findOne({_id:userId}, (err,data) => {
   if(err) console.log(err)
   let newExercise = new Exercise({
   description: description,
   duration: duration,
   date:date
   })
   const username = data.username
   newExercise.save((err,data) => {
     if(err) return console.log(err)
     res.json({
       _id: userId,
       description: description,
       duration: duration,
       date:new Date(date).toDateString(),
       username: username
     })
   })
 })

})

But despite it seems working well it doesn’t pass the test, the connection with mongo atlas is working so I don’t think that’s the problem, I can’t figure out what the problem is.
NB: I’ve posted a good part of the code but the important part is the one that begins with app.post(“/api/:id/exercises”…
Your project link(s)

solution: boilerplate-project-exercisetracker - Replit

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36

Challenge: Exercise Tracker

Link to the challenge:

Each exercise has to be added to the user that created it. Currently you are creating an Exercise without any reference to the user. One of the tests shows the expected format:

You can make a GET request to /api/users/:_id/logs to retrieve a full exercise log of any user. The returned response will be the user object with a log array of all the exercises added. Each log item has the description , duration , and date properties.

I’ve tried to change a bit the code but it still doesn’t pass the fourth test.

let schema = new mongoose.Schema({
  username: String,
   exercises: [
      {
        description: { type: String },
        duration: { type: Number },
        date: { type: String, required: false }
      }
    ]
})
let Users = mongoose.model("Users", schema)
const defaultDate = () => new Date().toISOString().slice(0, 10)
app.post("/api/users/:_id/exercises", (req,res) => {
 const userId = req.params._id
let exercises = {
  description: req.body.description,
  duration: req.body.duration,
  date: req.body.date || defaultDate()
}
 Users.findByIdAndUpdate(
    userId, 
    {$push: { exercises: exercises } },
    {new: true},
     (err, data) => {
      if(err) return console.log(err)
      let returnObj = {
        username: data.username,
        description: exercises.description,
        duration: exercises.duration,
       _id: userId,
        date: new Date(exercises.date).toDateString()
      };
      res.json(returnObj);
    }
  );

})

Even in this case it seems to work perfectly fine but the test doesn’t pass

Unfortunately there are no error messages for the tests. But the problem is quite trivial: in the response object, duration is supposed to be a Number not a String. However it is passed to the server (in req.body) as a string and you directly use this in the response.

let exercises = {
  description: req.body.description,
  duration: req.body.duration,   // <--- for example "60"
  date: req.body.date || defaultDate()
}
...
let returnObj = {
  username: data.username,
  description: exercises.description,
  duration: exercises.duration,  // <-- still "60", but expected: 60
  _id: userId,
  date: new Date(exercises.date).toDateString()
};
res.json(returnObj);

One easy way to avoid this:

let exercises = {
  ...
  duration: Number(req.body.duration), 
  ...
}

Or somewhat more complex, create an Exercise model in mongoose and use that. Since you set the type for duration as Number, this will automatically convert it. Then you can also use .validate() to check if it is actually a valid Exercise (in case you have something like duration = "asdf")

let exerciseSchema = new mongoose.Schema({
  description: { type: String, required: true },
  duration: { type: Number, required: true },
  date: { type: String }
})
let Exercise = mongoose.model("Exercise", exerciseSchema)
let schema = new mongoose.Schema({
  username: String,
   exercises: [ exerciseSchema ]
})
...
let exercises = new Exercise({
  description: req.body.description,
  duration: req.body.duration,
  date: req.body.date || defaultDate()
})
exercises.validate(err => {
  // Handle possible errors
})

Note: by default a field is not required, so instead of required: false on the date field, you want required: true on the other fields.

Now it works!!! Thank you very much

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.