Exercise Tracker, Mongo Duplicate key Error

Hello., Good day

Spent days on figuring this out, but to no avail.

I keep getting Duplicate _id key Error from my mongo, while trying to add exercises to the database from the same user.

Please, this is the link to my project.

My index.js document

const app = express()
const cors = require('cors')
require('dotenv').config()

app.use(cors())
app.use(express.static('public'))
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/views/index.html')
});


const mongoose = require('mongoose');

mongoose.connect(process.env.MONGO_URI);
//mongoose.prototype.connect no longer accepts a callback

const userSchema = mongoose.Schema({
  username: {
    type: String,
    unique: true,
  },
},
  { versionKey: false }
);


const User = mongoose.model("User", userSchema)
// const bodyParser = require('body-parser');


const exerciseSchema = mongoose.Schema({
  username: String,
  description: String,
  duration: Number,
  date: String,
  userid: { type: String, unique: false}
}, { versionKey: false });

const Exercise = mongoose.model("Exercise", exerciseSchema);





//* Middleware
app.use(express.urlencoded({ extended: true }));
//app.use(bodyParser.json());
// app.use(bodyParser.urlencoded({ extended: false }));

// GET request to /api/users-->
app.get("/api/users", async (req, res) => {
  const allUsers = await User.find()
  // console.log(allUsers)
  .then((user)=> {
    res.json(allUsers);
  })
})

app.post('/api/users', async (req, res) => {
  const username = req.body.username;
  const userFound = await User.findOne({ username });

  if (userFound) {
    res.json(userFound)
  }
  const user = await User.create({
    username,
  });

  res.json({ user });
});


// POST to /api/users/:_id/exercises
// {
//   username: "fcc_test",
//   description: "test",
//   duration: 60,
//   date: "Mon Jan 01 1990",
//   _id: "5fb5853f734231456ccb3b05"
// }


//I DON'T UNDERSTAND WHY THIS DOESN'T WORK, posting to api/users/:_id/exercises

app.post('/api/users/:_id/exercises', async (req, res) => {
  // const id = req.params._id;
  let { description, duration, date} = req.body;
  const userid = req.body[":_id"]; // it's good to use try and catch error while using async.
  const foundUser = await User.findById(userid);

  if (!date) {
    date = new Date();
    date = date.toDateString();
  }
  else {
    date = new Date(date);
    date = date.toDateString();
  }
console.log(userid);
  //Create Exercise data in the database, it will also be useful in the future for a specific user.
  await Exercise.create({
    username: foundUser.username,
    description,
    duration,
    date: date,
    _id: userid
  })

  res.json(
    {
      username: foundUser.username,
      description,
      duration,
      date: date,
      _id: userid

    }
  );

});

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

app.get("/api/users/:_id/logs", async (req, res) => {
  const userid = req.params._id;
  const foundUser = await User.findById(userid);
  if (!foundUser) {
    res.json({ message: "No user found" })
  }
  let exercises = await Exercise.find({ userid });
  try {
    exercises = exercises.map((exercise) => {
      return {
        description: exercise.description,
        duration: exercise.duration,
        date: exercise.date
      };
    })
  }
  catch { res.json({ message: "Counldm't map" }); }

  res.json({
    username: foundUser.username,
    count: exercises.length,
    _id: userid,
    logs: exercises,
  });

});







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

I really appreciate any response please :pray:

  • have you tried putting this within a “conditional block” instead?
  • have a conditional check before doing that so that its not trying to create a “duplicate” record

happy coding :slight_smile:

But the goal is to create another Exercise record for the same user, with the same _id. That’s what we want. MongoDb does not suppose to impose unique index on the id. But in User database, id is unique.

I hope you get me sir?

You are creating an exercise using the userid for the exercise _id property, it won’t work because the _id for each exercise should be unique. You can create a relationship to the user, but not like that.

I would instead suggest you update the user to have a log field as an array and add the exercises to that. Your log endpoint will need to be reworked as well because of this.

In the /api/users route you are mixing async/await with .then() code. Either you await and use allUsers for the res.json() or you .then() and use the parameter for the res.json()

Your response from the /api/users POST route should not be inside an object so just user and not {user}

In the /api/users/:_id/exercises POST route the id is not on the body, it is a params. Both are undefined right now because of the wrong response in the /api/users POST route. After you fix that you can log out the body and params to verify the id in fact is a params.

The duration property in the /api/users/:_id/exercises response should be of type Number. You are not using the newly created exercise so the conversion only happens in the DB and you return the duration string you got from req.body (convert it or use the new exercise returned).

1 Like

I really appreciate this sir. It worked!