0

The goal of this program is to add a property called 'userResponse' to the problem objects that reflects the input from the user. The problem object in Mongo DB is held in an array of objects, called 'problems', that is held in an object called 'session':

{
    "_id" : ObjectId("59df5ee7adb378237377dbb4"),
    "updatedAt" : ISODate("2017-10-12T12:24:07.269Z"),
    "createdAt" : ISODate("2017-10-12T12:24:07.269Z"),
    "userId" : "59df5edbadb378237377dbb3",
    "problems" : [
        {
            "correctResponse" : 23,
            "problem" : "20 + 3",
            "secondTerm" : 3,
            "firstTerm" : 20
                } ]
}

Here is the logic for the endpoint that I have been using:

router.patch( '/session/:sessionId/:index', passport.authenticate( 'jwt', { session: false } ), ( req, res ) => {
    Session.findOne({_id: req.params.sessionId})
    .then( (item)=>{
        item.problems[req.params.index].userResponse = req.body.userResponse;
        Session.update({_id: req.params.sessionId}, item).then( (updated)=>{
          res.json(updated.problems[req.params.index]);
        }); 
    })

}) 

I looked at some other examples ( one two ) but they do not seem relavant since this is a patch to single elements of the array as identified by the params.

This approach works, in that it successfully updates the database with the new properties on the objects, but during the execution the server logs this error:

(node:10955) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property '0' of undefined

My understanding is that this means the object can not be found in the database at some point, but since the database does include the new properties it must be resolved later. Is that corrrect?

Additionally it seems brittle to have two chained promises with no catch statements...

Can anyone offer suggestions on how to improve this process? This logic does successfully update the database, with errors. Is there a better way?

Thank you for your time.

Cameron
  • 135
  • 1
  • 13

1 Answers1

1

Well i can see multiple issues in the code that can cause your problem

1- From the structure of your database session document _id is of type ObjectId and when you try to find, you are finding by just the id which is probably string you will need to use ObjectId(req.params.sessionId)

2- from the error, i can tell that the value of item does not contain an array of problems ... so items.problems is undefined so undefined[0] is an error.

3- You don't need to find session document item twice to update the array, i updated the code to update the userResponse value in array by using a single update operation.

4- for a better error handling and code maintainability you need to handle promise rejection so you need to handle catch as well as you are doing with then

So from the above comments i can update your code to be

var mongoose = require('mongoose');
router.patch( '/session/:sessionId/:index', passport.authenticate( 'jwt', { session: false } ), ( req, res ) => {
    var index = req.params.index;
    Session.update({_id: mongoose.Types.ObjectId(req.params.sessionId) }, {$set : {"problems." + index +  ".userResponse" : req.body.userResponse } )
    .then( (updated)=>{
      console.log(updated);
      res.json(updated.problems[req.params.index]);
    })
    .catch((err) => {
      console.log(err.message);
      res.json({status: "error" , message:err.message});
    });
}) 
Amr Labib
  • 3,995
  • 3
  • 19
  • 31
  • Excellent! Thank you very much for your time, I am new to Mongo/Mongoose and this is a big help. – Cameron Oct 12 '17 at 18:17
  • You are welcome :) ... glad it helped ... please if this answered your question mark it as accepted ... – Amr Labib Oct 12 '17 at 22:53