Back End Development and APIs Projects - Exercise Tracker

Tell us what’s happening:

I don’t understand why there are two tests that I don’t pass. Given what I see, the information is being given. I’ve been trying to understand for 3 days. Please, someone help me.

require(‘dotenv’).config();
const express = require(‘express’);
const app = express();
const cors = require(‘cors’);
const bodyParser = require(‘body-parser’);
const mongoose = require(‘mongoose’);
const { Schema } = mongoose;

/** Constants */
const ID_LENGTH = 24;
const MINLENGTH = [3, ‘Must have at least 3 characters - you entered {VALUE}’];
const IDLENGTH = [ID_LENGTH, Must be ${ID_LENGTH} characters long - you entered {VALUE}];

/** Schemas */
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
dropDups: true,
trim: true,
minLength: MINLENGTH
}
}, { autoIndex: false });

const exerciseSchema = new Schema({
userid: {
type: String,
required: true,
trim: true,
minLength: IDLENGTH,
maxLength: IDLENGTH
},
description: {
type: String,
required: true,
trim: true,
minLength: MINLENGTH
},
duration: {
type: Number,
required: true,
min: [1, ‘Must be at least 1 minute long’]
},
date: {
type: Number,
required: true
}
}, { autoIndex: false });

/** Models */
const User = mongoose.model(“User”, userSchema);
const Exercise = mongoose.model(“Exercise”, exerciseSchema);

/** Connect to database */
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });

/** Middleware */
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(cors());
app.use(express.static(‘public’));

/** Routes */
app.get(‘/’, async (req, res) => {
res.sendFile(__dirname + ‘/views/index.html’);
});

// Create a new user
app.post(‘/api/users’, async (req, res) => {
try {
const { username } = req.body;
const newUser = new User({ username });
const savedUser = await newUser.save();
res.json({ username: savedUser.username, _id: savedUser._id });
} catch (error) {
res.status(400).json({ error: error.message });
}
});

// Get a list of all users
app.get(‘/api/users’, async (req, res) => {
try {
const users = await User.find({}, ‘username _id’);
res.json(users);
} catch (error) {
res.status(400).json({ error: error.message });
}
});

// Add an exercise for a specific user
app.post(‘/api/users/:_id/exercises’, async (req, res) => {
try {
const { description, duration, date } = req.body;
const userid = req.params._id;
const newExercise = new Exercise({
userid,
description,
duration,
date: date ? new Date(date).getTime() : new Date().getTime()
});
const savedExercise = await newExercise.save();
res.json({ _id: savedExercise.userid, username: savedExercise.username, description, duration, date: savedExercise.date });
} catch (error) {
res.status(400).json({ error: error.message });
}
});

// Get full exercise log of any user
app.get(‘/api/users/:_id/logs’, async (req, res) => {
try {
const userid = req.params._id;
const { from, to, limit } = req.query;
const query = { userid };
if (from || to) {
query.date = {};
if (from) query.date.$gte = new Date(from).getTime();
if (to) query.date.$lte = new Date(to).getTime();
}
const exercises = await Exercise.find(query).limit(parseInt(limit) || undefined);
res.json({ _id: userid, count: exercises.length, log: exercises });
} catch (error) {
res.status(400).json({ error: error.message });
}
});

/** Start the server */
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(Server is running on port ${PORT});
});

image

###Your project link(s)

githubLink: GitHub - josedev-front/boilerplate-project-exercisetracker: A boilerplate for a freeCodeCamp project.

solution: http://localhost:3000

Your browser information:

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

Challenge Information:

Back End Development and APIs Projects - Exercise Tracker

but please explain to me what exactly refers to test 8,

image

If I add a user, it is added fine

image

but, the user object with the exercise fields added. needs to be in especific order or format ?

When I submit and look at it in the browser duration is not the correct data type.

POST: http://localhost:3000/api/users/66293881cbcac311752cbaee/exercises

Response:

{
    "_id": "66293881cbcac311752cbaee",
    "username": "fcc_test_17139774731",
    "description": "test",
    "duration": "60",
    "date": "Mon Jan 01 1990"
}

You are using the req.body string for the response and not the duration you get back from the model. So any conversion done by the schema is lost in your response.

in this case @lasjorg , if duration is not a correct data type (Number), the correct is date type?

require('dotenv').config();
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const { Schema } = mongoose;

/** Constants */
const ID_LENGTH = 24;
const MINLENGTH = [3, 'Must have at least 3 characters - you entered {VALUE}'];
const IDLENGTH = [ID_LENGTH, `Must be ${ID_LENGTH} characters long - you entered {VALUE}`];

/** Schemas */
const userSchema = new Schema({
  username: {
    type: String,
    required: true,
    unique: true,
    dropDups: true,
    trim: true,
    minLength: MINLENGTH
  }
}, { autoIndex: false });

const exerciseSchema = new Schema({
  userid: { 
    type: String, 
    required: true,
    trim: true,
    minLength: IDLENGTH,
    maxLength: IDLENGTH
  },
  description: { 
    type: String, 
    required: true,
    trim: true,
    minLength: MINLENGTH
  },
  duration: { 
    type: Number, 
    required: true,
    min: [1, 'Must be at least 1 minute long']
  },
  date: { 
    type: Date, // Cambiado a tipo Date
    required: true
  }
}, { autoIndex: false });

const checkDate = (date) => {
  if (!date) {
    return new Date(); // Devuelve la fecha actual si no se proporciona ninguna fecha
  } else {
    const parts = date.split('-');
    const year = parseInt(parts[0]);
    const month = parseInt(parts[1]) - 1;
    const day = parseInt(parts[2]);
    return new Date(year, month, day); // Devuelve un objeto de fecha
  }
};

/** Models */
const User = mongoose.model("User", userSchema);
const Exercise = mongoose.model("Exercise", exerciseSchema);

/** Connect to database */
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });

/** Middleware */
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use(cors());
app.use(express.static('public'));

/** Routes */
app.get('/', async (req, res) => {
  res.sendFile(__dirname + '/views/index.html');
});

// Create a new user
app.post('/api/users', async (req, res) => {
  try {
    const { username } = req.body;
    const newUser = new User({ username });
    const savedUser = await newUser.save();
    res.json({ username: savedUser.username, _id: savedUser._id });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Get a list of all users
app.get('/api/users', async (req, res) => {
  try {
    const users = await User.find({}, 'username _id');
    res.json(users);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

app.post('/api/users/:_id/exercises', async (req, res) => {
  try {
    const { description, duration, date } = req.body;
    const userid = req.params._id;
    
    // Formatear la fecha utilizando la función checkDate()
    const formattedDate = checkDate(date);

    // Guardar el nuevo ejercicio en la base de datos
    const newExercise = new Exercise({
      userid,
      description,
      duration,
      date: formattedDate
    });
    const savedExercise = await newExercise.save();

    // Obtener el usuario al que pertenece este ejercicio
    const user = await User.findById(userid);

    // Combinar los campos del ejercicio con los del usuario
    const response = {
      _id: user._id,
      username: user.username,
      description,
      duration,
      date: formattedDate // Usar la fecha formateada
    };
    console.log('Response:', response);
    // Devolver la respuesta combinada
    res.json(response);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});
// Add an exercise for a specific user
/*app.post('/api/users/:_id/exercises', async (req, res) => {
  try {
    const { description, duration, date } = req.body;
    const userid = req.params._id;
    
    // Formatear la fecha utilizando la función checkDate()
    const formattedDate = checkDate(date);

    // Guardar el nuevo ejercicio en la base de datos
    const newExercise = new Exercise({
      userid,
      description,
      duration,
      date: formattedDate.toDateString() // Formatear la fecha utilizando toDateString()
    });
    const savedExercise = await newExercise.save();
    // Obtener el usuario al que pertenece este ejercicio
    const user = await User.findById(userid);

    // Combinar los campos del ejercicio con los del usuario
    const response = {
      _id: user._id,
      username: user.username,
      description,
      duration,
      date: formattedDate.toDateString() // Formatear la fecha utilizando toDateString()
    };

    // Imprimir el objeto response en la consola
    console.log('Response:', response);

    // Devolver la respuesta combinada
    res.json(response);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});*/


// Get full exercise log of any user
app.get('/api/users/:_id/logs', async (req, res) => {
  try {
    const userid = req.params._id;
    const { from, to, limit } = req.query;
    const query = { userid };

    // Verificar si los parámetros from y to son fechas válidas
    const fromDate = from ? new Date(from) : null;
    const toDate = to ? new Date(to) : null;
    if ((from && isNaN(fromDate.getTime())) || (to && isNaN(toDate.getTime()))) {
      return res.status(400).json({ error: "Las fechas from y to deben estar en formato aaaa-mm-dd." });
    }

    // Construir el filtro de fecha
    if (fromDate || toDate) {
      query.date = {};
      if (fromDate) query.date.$gte = fromDate;
      if (toDate) query.date.$lte = toDate;
    }

    // Ejecutar la consulta a la base de datos con la limitación de registros
    let exercisesQuery = Exercise.find(query);
    if (limit) exercisesQuery = exercisesQuery.limit(parseInt(limit));

    const exercises = await exercisesQuery;

    // Mapear las fechas a formato de cadena de texto utilizando el método toDateString()
    const formattedExercises = exercises.map(exercise => ({
      ...exercise._doc,
      date: new Date(exercise.date).toDateString()
    }));

    // Agregar un console log para ver los ejercicios formateados
    console.log('formattedExercise:', formattedExercises);

    // Devolver la respuesta con el registro de ejercicios
    res.json({ _id: userid, count: formattedExercises.length, log: formattedExercises });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});app.get('/api/users/:_id/logs', async (req, res) => {
  try {
    const userid = req.params._id;
    const { from, to, limit } = req.query;
    const query = { userid };

    // Verificar si los parámetros from y to son fechas válidas
    const fromDate = from ? new Date(from) : null;
    const toDate = to ? new Date(to) : null;
    if ((from && isNaN(fromDate.getTime())) || (to && isNaN(toDate.getTime()))) {
      return res.status(400).json({ error: "Las fechas from y to deben estar en formato aaaa-mm-dd." });
    }

    // Construir el filtro de fecha
    if (fromDate || toDate) {
      query.date = {};
      if (fromDate) query.date.$gte = fromDate;
      if (toDate) query.date.$lte = toDate;
    }

    // Ejecutar la consulta a la base de datos con la limitación de registros
    let exercisesQuery = Exercise.find(query);
    if (limit) exercisesQuery = exercisesQuery.limit(parseInt(limit));

    const exercises = await exercisesQuery;

    // Mapear las fechas a formato de cadena de texto utilizando el método toDateString()
    const formattedExercises = exercises.map(exercise => ({
      ...exercise._doc,
      date: new Date(exercise.date).toDateString()
    }));

    // Agregar un console log para ver los ejercicios formateados
    //console.log('formattedExercise:', formattedExercises);

    // Devolver la respuesta con el registro de ejercicios
    res.json({ _id: userid, count: formattedExercises.length, log: formattedExercises });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});


/** Start the server */
const listener = app.listen(process.env.PORT || 3000, () => {
  console.log('Your app is listening on port ' + listener.address().port)
});

It should be type Number. Look at your route code. I added some comments.

app.post('/api/users/:_id/exercises', async (req, res) => {
  try {
    // duration is of type string
    const { description, duration, date } = req.body;
    const userid = req.params._id;
    
    // Formatear la fecha utilizando la función checkDate()
    const formattedDate = checkDate(date);

    // duration is converted but never used for the response
    const newExercise = new Exercise({
      userid,
      description,
      duration,
      date: formattedDate
    });
    const savedExercise = await newExercise.save();

    // Obtener el usuario al que pertenece este ejercicio
    const user = await User.findById(userid);

    // duration is still type string
    const response = {
      _id: user._id,
      username: user.username,
      description,
      duration,
      date: formattedDate // Usar la fecha formateada
    };
    console.log('Response:', response);
    // Devolver la respuesta combinada
    res.json(response);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

@lasjorg

I modified the function, and even added a console.log and typeof to see what the app.post(‘/api/users/:_id/exercises’ returned
, but the problem continues, I leave the console image, which confirms that duration is number

app.post('/api/users/:_id/exercises', async (req, res) => {
  try {
    const { description, duration, date } = req.body;
    const userid = req.params._id;

    const newExercise = new Exercise({
      userid,
      description,
      duration,
      date: date ? new Date(date) : new Date()
    });
    const savedExercise = await newExercise.save();

    const user = await User.findById(userid);

    const response = {
      _id: user._id,
      username: user.username,
      description,
      duration: savedExercise.duration, // Utilizar el valor de duración del ejercicio guardado
      date: new Date(savedExercise.date).toDateString()
    };
    console.log('Tipo de datos de duration en el response:', typeof response.duration); 
    console.log('Response:', response);
    res.json(response);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

image
image

Did you restart the server?

Your new code is giving me the correct response and is passes all the tests.

@lasjorg
i reestart the server, the browser, try with private tab , an the problem persist , i dont know What else can I try?

i’am using , visual studio code, github , and the local host, y read in a other post ,
it could be the time zone.

To be honest I don’t understand the logic of the time zone.

Try using toUTCString instead.

Edit: I guess the format is quite correct, so you might have to reformat it.


To toLocaleDateString might be better. It is what some of the tests use as well.

Try figuring out the options needed. But just in case, I will post the options object that should work.

{
  timeZone: "UTC",
  weekday: "short",
  month: "short",
  day: "2-digit",
  year: "numeric",
}

You can also just set your PC timezone to UTC (no plus or minus) and call it a day (if it works, which it should).

i try with

toLocaleString()
toISOString()
toUTCString()

and nothing happens

No LLM answers please

I changed my PC timezone to UTC-03:00 and use toLocaleDateString and it passed the tests. Your commit history is pretty chaotic, so I can’t tell you what version of your code I’m using. I can see you have added a date lib, that is also an option.

I might suggest you save the date converted to the UTC timezone so you can just call toDateString on the saved date in the other places that uses the date.

Some console logs using UTC-03:00

new Date('1990-01-01').toDateString()
// 'Sun Dec 31 1989'

new Date("1990-01-01")
  .toLocaleDateString("en-US", {
    timeZone: "UTC",
    weekday: "short",
    month: "short",
    day: "2-digit",
    year: "numeric",
  })
  .replaceAll(",", "");
  
// 'Mon Jan 01 1990'