David Reke
David Reke

Reputation: 555

Blank document and unhandled promise rejection when making an add subdocument request

I am working on my first request that would add a subdocument to a document in MongoDB and I'm struggling with it. My database is a collection of users, and each user has an array of words they working on learning to translate in the application I am building. I am currently having two issues

  1. when I make a request in postman to add a new word to my user's array of words, I add a new object that has ID, but none of the other property value pairs that I have in the word sub-model, and in the request(greek, english, success, timestamp).

  2. my command prompt gives me the following errors

(node:8320) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3) (node:8320) UnhandledPromiseRejectionWarning: ValidationError: user validation failed: words.0.greek: Path greek is required., words.0.english: Path english is required., words.0.success: Path success is required., words.0.timeStamp: Path timeStamp is required.

The second error is confusing because in my mind it should be word.greek and words.english to get the value from the each word object. However, it adds a 0 between the object and its property/value pair.

My mongoose model for the subdocument is as follows

const wordSchema = new Schema({
  greek: {
    type: String,
    required: true,
    trim: true,
    minlength: 1,
    index: { unique: true, sparse: true },
  },
  english: {
    type: String,
    required: true,
    minlength: 1
  },
  success: {
    type: Number,
    required: true
  },
  timeStamp: {
    type: Date,
    required: true
  },
});

This is my request to add the word to the User's array of words.

router.post("/update/:id",(req, res) =>{
    console.log(req.body.greek)
    var greek = req.body.greek;
    var english = req.body.english;
    var success = req.body.success;
    var timeStamp = req.body.timeStamp
    var newWord = {
        greek: greek,
        english: english,
        success: success,
        timeStamp: timeStamp
    }
    User.findById(req.params.id)
    .then((user) => {
      user.words.push(newWord);
      user.save()
      res.status(200).json(user)
      .catch((err) => {res.status(400).json(err)})
    })
    .catch((err) => {res.status(400).json("Error: "+err)})
});

Any help would be greatly appreciated! I've done some googling on adding subdocuments to a document, but I still haven't found the solution.

Upvotes: 0

Views: 69

Answers (2)

LostJon
LostJon

Reputation: 2387

one thing I see is user.save() will return a promise, which you do not handle, hence the document will not be save. maybe consider:

User.findById(req.params.id)
.then(async (user) => {
    user.words.push(newWord);
    await user.save()
    res.status(200).json(user)
    .catch((err) => {res.status(400).json(err)})
})
.catch((err) => {res.status(400).json("Error: "+err)})

Upvotes: 1

malong11
malong11

Reputation: 678

Instead of fetching and then updating the document you can directly update the document in one DB call.

router.post("/update/:id",(req, res) =>{
    console.log(req.body.greek)
    var greek = req.body.greek;
    var english = req.body.english;
    var success = req.body.success;
    var timeStamp = req.body.timeStamp
    var newWord = {
        greek: greek,
        english: english,
        success: success,
        timeStamp: timeStamp
    }
    User.findOneAndUpdate({ _id: req.params.id }, {
            $push: {
                words: newWord
            }
        })
    .then((user) => {
      if(!user){
                return res.status(404).json({ 
                    message: 'Not User matches given ID'
                });
            }

            res.status(200).json(user);
    })
    .catch((err) => {res.status(400).json("Error: "+err)})
});

Upvotes: 2

Related Questions