4 Days, can't solv: Exercise Tracker - Tests 8 & 15 not passing

Tell us what’s happening:
I’m tearing my hair out with these two tests, and it seems like this is a really common struggling point for the challenge.

I’m properly managing the date format when it’s not included (param.date as well as today’s date if null are being stored as date objects), then I use .toDateString() and am able to convert to a string for the return output.

Test number 8:
The response returned from api/users/:id/exercises will be the user object with the exercise fields added.

I’ve written the challenge with two different sets of Schemas, currently doing an “all in one” Schema:

let userSchema = new Schema({
  username: {
    required: true,
    type: String
  },
  log: [{
    description: String,
    duration: Number,
    date: Date
  }]
});

And am able to log exercises as expected. My return result from the POST is this, which to me looks like it meets the criteria, but it isn’t passing.

 {
  username: 'fcc_test_16748829723',
  _id: new ObjectId("63d4af9c2ba075d08fe744ca"),
  description: 'test',
  duration: 60,
  date: 'Sat Jan 28 2023'
}

I’m very confused if the key value pair I’m getting after saving my user object:
_id: new ObjectId("63d4af9c2ba075d08fe744ca")
is identical to this format which seems like what I usually see:
_id: "63d4af9c2ba075d08fe744ca"
And I wonder if that’s causing any issues.

Test number 15 I’m also not passing seems similar, but in this case, for the life of me I can’t cast the date obect to a string, even though I have tried a variety of toString() functions including toDateString() and toISODateString

This is my returned JSON for the api/users/:id/logs, and on screen it looks fine but again not passing. The date is being returned in what seems like an object, and attempt to convert to a string is below, using ‘map’ :

exerciselog:  {
  username: 'fcc_test_16748829723',
  _id: new ObjectId("63d4af9c2ba075d08fe744ca"),
  count: 1,
  log: [
    {
      description: 'test',
      duration: 60,
      date: 2023-01-28T05:16:12.622Z,
      _id: new ObjectId("63d4af9c2ba075d08fe744cc")
    }
  ]
}

I am using Model.findOneAndUpdate like so:

User.findByIdAndUpdate({ _id: userID }, { $push: { log: newExercise } }, { new: true }, function(err, user) { 
// error handling
// create return object with dates to strings (but isn't actually converting)
// return exercise log
}

Here is how I’m handling the exercise log to try and convert to strings before returning:

    { description: 'test', duration: 60, date: 1990-01-01T00:00:00.000Z }

      workingLog.map(item => item.date.toDateString())


      let exerciseLog = {
        "username": user.username,
        "_id": user._id,
        "count": workingLog.length,
        "log": workingLog
      }

Code source is below. Thank you in advance for any input, this is driving me crazy!

Your project link(s)

solution: boilerplate-project-exercisetracker - Replit

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36

Challenge: Back End Development and APIs Projects - Exercise Tracker

Link to the challenge:

For the first test, your code is not sending the data as the correct types. It’s either the duration not being sent as an integer (most likely) or the _id not being sent as a string (it should be already). This test checks deep equality and the types and values have to match.

For the second, you have the problem in your output already:

That should be date string like used elsewhere.

Finally, you have some minor errors that you may want to fix. Returning

return console.log(err);

for instance, does not return the error err but rather the return value of console.log(). The POST user route should be asynchronous and is not. It’s working because the code executes quickly but doing an asynchronous user.save() without handling it and subsequently using the values can lead to difficult to find problems.

1 Like

You should look at the responses in the network tab when submitting, comparing them to the examples given.


The /api/users/:_id/exercises is returning this:

{"returnRes":{"username":"fcc_test_16749321922","_id":"63d56fe06a420f94feeb84d7","description":"test","duration":60,"date":"Mon Jan 01 1990"}}

This is the example return:

{
  username: "fcc_test",
  description: "test",
  duration: 60,
  date: "Mon Jan 01 1990",
  _id: "5fb5853f734231456ccb3b05"
}

The /api/users/:_id/logs is returning this:

{"username":"fcc_test_16749321934","_id":"63d56fe16a420f94feeb84e1","count":1,"log":[{"description":"test","duration":60,"date":"2023-01-28T18:56:34.041Z","_id":"63d56fe26a420f94feeb84e3"}]}

This is the example return:

{
  username: "fcc_test",
  count: 1,
  _id: "5fb5853f734231456ccb3b05",
  log: [{
    description: "test",
    duration: 60,
    date: "Mon Jan 01 1990",
  }]
}

It looks like the issue with test 8 is that the returned object is not in the format specified in the test. The returned object should have an array of exercises as a property of the user object, rather than having the exercise properties directly on the user object.

In test 15, it looks like the date is being returned as a JavaScript Date object, rather than a string. It appears that you’re trying to use the .toDateString() method to convert the date to a string, but this method returns the date in the format “Month Day Year”. You can try using the .toISOString() method to convert the date to a string in the format “Year-Month-DayTTime:Time:Time.MillisecondsZ”, which is the format specified in the test.

Also, in the code snippet you’ve shared, it seems that you’re trying to convert the date to a string using map method on the workingLog array. But you need to update the date property inside the array.

Try the following code:

workingLog.forEach(item => {
    item.date = item.date.toISOString();
});

And also, it seems that you’re using mongoose’s findByIdAndUpdate function, which returns the original document before the update by default. To get the updated document, you need to pass { new: true } as the options.

Try the following code:

User.findByIdAndUpdate({ _id: userID }, { $push: { log: newExercise } }, { new: true }, function(err, user) {
    // error handling
    // create return object with dates to strings (but isn't actually converting)
    // return exercise log
});

Hope this helps! Let me know if you have any questions.

Thanks for all the suggestions, i’ll take a look through all of them and try to fix this tomorrow!

Hi, this is part that is really confusing me, because the challenge is written this way:

The response returned from POST /api/users/:_id/exercises will be the user object with the exercise fields added.

So I’m interpreting that as the following response which is what is in the challenge description, and assuming that should be the POST response.

Exercise:

{
  username: "fcc_test",
  description: "test",
  duration: 60,
  date: "Mon Jan 01 1990",
  _id: "5fb5853f734231456ccb3b05"
}

The embedded exercise log is for the GET /logs response. I know there are other issues, but this one is confusing the way the challenge is written and looking at the actual test, it looks like is expecting a flat object.

Am i reading the challenge incorrectly?

shouldn’t _id be a number?

When I try to post the exercise with the _id grabbed from req.body, the test prior fails. #7:
You can POSTto/api/users/:_id/exerciseswith form datadescription,duration, and optionallydate . If no date is supplied, the current date will be used.

casting to a number also didn’t work but when I cast to an object ID, it passed the test, but then the returned object has a new object as the actual objecct ID.

I feel like when I pass one test I fail the next test and just keep going back and forth. So there is probably a more fundamental problem in my code.

I’ll keep looking, and try your other suggestions too.

This is my original code which I think is identical to what you posted:

User.findByIdAndUpdate({ _id: userID }, { $push: { log: newExercise } }, { new: true }, function(err, user) { 
// error handling
// create return object with dates to strings (but isn't actually converting)
// return exercise log
}

It is utilizing MongoDB’s driver for Node.js to update a document in a MongoDB collection, it is using the findByIdAndUpdate() function to find a document by its _id field, in this case, the userID. The function then updates the document by adding a new object, ‘newExercise’ to the “log” array field of that document. This method also returns the updated document and sets the new option to true, so the updated version of the document will be returned in the callback function. It also includes error handling, converting dates to strings, and returning the updated exercise log.

I really appreciate your time…I’m already using that though. The challenge seems to call for a “flat” response which means using some JS to create the appropriate object. It seems unnecessary to do so for practical use, but I assume it’s just part of doing the work to pass the test.

I’m going to take a break and come back when my brain is more rested

I understand that the task you are working on requires a specific format, which may not be practical but is necessary to pass the test. It requires you to use JavaScript to create the appropriate object and return a "flat" response. I’m glad that my previous response was helpful to you, and I acknowledge that taking a break and coming back to it with a fresh mind can be beneficial. Please let me know if you need any further assistance, I’ll be happy to help you.

What you’re logging and what you’re sending are not the same thing. I debugged a fork of your code by explicitly setting the types; I just didn’t bother to determine which was the actual problem since it’s usually duration.

duration has to be an integer. _id has to be a string; mongoose objects IDs should be automagically coerced to string when sending a JSON response (by res.json()), but adding a .toString() never hurts.

1 Like

Thanks so much, I’ll give it another shot!

Alright, taking another look, I checked the network / response tab to see what was being returned, and this is what I get for the response from post exercise route:


{"returnRes":{"username":"fig","_id":"63d77a24568457b6f6e3190d","description":"sleep","duration":4,"date":"Sat Jan 01 2022"}}

Geez, you’re good. I have never used the network tab like that to check the response, that’s crazy! But I’m wondering now how do I assign a variable to return without it returning it as an object within an object? Hmm, maybe object notation? In any case I have test #8 passing now, onto test #15. Thank you!

thank you. I read this reply several times not understanding why you wrote it , because it didn’t seem to provide me with useful information…that is, until I passed test #8, and now I 100% understand what you are writing. Thanks for your patience in helping

I already replied to this once, but when you wrote this, i literally could not see the difference between my response and the example response, even thought you spelled it out. It’s so strange how the brain works sometimes, it doesn’t see what you don’t know!

I hope that I solved your problem.

Half of it! I’m still working on #15, very close…

Test #8: The returned user object from api/users/:id/exercises is failing the criteria despite being seemingly correct. The schema combines username and exercise logs into one. The data returned by POST request includes username, user ID, description, duration, and date in correct format, however the user ID is returned in a different format than expected (_id: new ObjectId("63d4af9c2ba075d08fe744ca") instead of _id: "63d4af9c2ba075d08fe744ca"). This difference could be causing issues.

Test #15: The returned JSON from api/users/:id/logs is failing the test, although it appears to be correct. The date in the exercise log is an object, but converting it to string using toDateString() or other toString() methods has been unsuccessful. The code uses Model.findOneAndUpdate to update user data and generates the exercise log by mapping over the working log, but the date conversion is not happening.

Use the dateString format of the Date API.

You can compare the two inside your workingLog map loop before the return.

console.log('toString', item.date.toString())
console.log('toDateString', item.date.toDateString())

Using toDateString with your code makes it pass all the tests for me.