Search code examples
javascriptnode.jsmongodbmongoosepostman

Cannot modify a String in a MongoDb Database with router.post()


I created an object within my MongoDb database. The object has the following scheme:

var goalsSchema = new mongoose.Schema({
  types: [String],
  start: String,
  end: String,
 });

 var userSchema = new mongoose.Schema({
  name: String,
  surname: String,
  email: String,
  goals: [goalsSchema],
    });

When I insert the object, through router.post(), everything works fine, But when I try to add a string inside the Types property, it doesn't work. The terminal tells me that everything worked, with code 200, but in reality the database is not updated.

This is code inside index.js:

const mongoose = require("mongoose");

mongoose
  .connect("mongodb://127.0.0.1:27017/meditactive", {
    useUnifiedTopology: true,
    useNewUrlParser: true,
  })
  .then(() => console.log("Server connected"))
  .catch((err) => console.log(err));

var db = mongoose.connection;

const goalsRouter = require("./routes/goals");

app.use(express.json());
app.use(mongoSanitize());

app.use("/api/goal", goalsRouter);

app.listen(3000);

while this is the one within routes/goals:

const mongoose = require("mongoose");

router.post("/:id/goals/:idgoal/edit", (req, res) => {
  const { id } = req.params;
  const { idgoal } = req.params;
  const goalInsert = req.body;

  User.findById(id)
    .then((user) => {
      if (user) {
        const goalToModify = user.goals.find(
          (goal) => goal._id.toString() === idgoal
        );
        console.log(goalToModify);

        if (goalToModify) {
          goalToModify.types.push(goalInsert);
          user.markModified("goals");
          user
            .save()
            .then(() => {
              res.status(200).json({ message: "Goals added" });
            })
            .catch((err) => {
              res.status(500).json({ error: err });
            });
        } else {
          res.status(500).json({ error: err });
        }
      }
    })
    .catch((err) => {
      res.status(500).json({ error: err });
    });
});

I make the request with Postman, I send a string between double quotes, I receive the message: Goals added but inside types I see an empty object and not my string


Solution

  • For this type of update you can use mongoose findOneAndUpdate() method. I will give an example using async/await as you seem to be heading for nested then blocks which can cause issues as your application grows.

    router.post("/:id/goals/:idgoal/edit", async (req, res) => { //< Note the use of async keyword
    
       try { // Wrap in a try catch for cleaner error handling
          const { id } = req.params;
          const { idgoal } = req.params;
          const goalInsert = req.body;
    
          const user = await User.findOneAndUpdate( //< Note the use of await
                {
                    _id: new mongoose.Types.ObjectId(id), //< Find user with this _id
                    "goals._id": new mongoose.Types.ObjectId(idgoal), // But also with this idgoal
                },
                {
                   $push: { //< Push in the goals.types array
                      "goals.$.types": goalInsert
                   }
                }, {new: true} //< This option returns the updated document
         ); 
         console.log(user);
    
         res.status(200).json({ message: "Goals added" });
    
       } catch(err){
          res.status(500).json({ error: err });
       }
    });
    

    This uses $push to push the items to your types array.

    If however, you need the types array to be a unique list of values in the array then you will need to use $addToSet instead like so.

    const user = await User.findOneAndUpdate( //< Note the use of await
       {
          _id: new mongoose.Types.ObjectId(id), //< Find user with this _id
          "goals._id": new mongoose.Types.ObjectId(idgoal), // But also with this idgoal
       },
       {
          $addToSet: { //< Add unique value in the goals.types array
             "goals.$.types": goalInsert
          }
       }, {new: true} //< This option returns the updated document
    );