Issue Tracker Node.js Test Problems - Not passing test #10 and #7

Hi campers,

I’ve been wrestling with the Issue Tracker in Quality Assurance, and I think I’m missing some core concept about editing/updating a subdocument in a document.

I am using Mongoose over MongoDB, so maybe that makes a difference. The way I’ve structured the schema is that each project has a ‘caselog’ array of issue objects. (I initially didn’t understand that the issues themselves were a sub-component of project, and that took me a while to understand).

I can’t get the API route DELETE and PUT to pass the tests. I think what is tripping me up is the editing of the array inside the of the project, and then how to “save” that back to the database.

Here is the Schema and setup:

//building a new Schema
const Schema = mongoose.Schema;
const issueSchema = new Schema({
  project: {type:String, required: true},
  caselog: [
    {issue_title: {type:String, required: true},
    issue_text: {type:String, required: true},
    created_by: {type:String, required: true},
    created_on: Date,
    updated_on: Date,
    assigned_to: {type: String, default: ''},
    open: {type: Boolean, default: true},
    status_text: {type: String, default: ''}
    }
  ]

})

//building a new model from the schema
const Issue = mongoose.model('Issue', issueSchema);

Here’s a sample of the DELETE route:

   .delete(function (req, res){
      let project = req.params.project;
      const issueId = req.body._id;
      if (issueId === null){
        return res.json({error: 'missing _id'});
      } else {
        //find item
        //slice from caselog list to remove
        //then save the data[0] again
        model.find({project:project}).exec(function(err,data){
          if (err) return (err);
          for (let element of data[0].caselog){
            const elementId = element._id.toString();
            if (elementId === issueId){
              //finds Id
              const elementIndex = data[0].caselog.indexOf(element);
              const removedItem = data[0].caselog.splice(elementIndex, 1);
              return data[0].save(function(err, result){
                if(err) return (err);
                res.json({result: 'successfully deleted', _id: issueId});
              })
            }
          }
          return res.json({error: 'could not delete', _id: issueId});
        })    
      }
    });

Here’s my Repl.it:

Repl.it - issuetracker

Some general questions:

  • In what instances should I be using MongoDB versus Mongoose?
  • Are there built-in methods in Mongoose that allows me to update a subdoc directly? I feel like I’m relying back on JS data structures to compensate for my lack of Mongoose knowledge, and it’s not very efficient.
  • I also know that I haven’t written the functional tests yet, and that may help me pinpoint why the code doesn’t pass the tests.

Shouldn’t it be Issue.find rather than model.find?

Mongoose subdocs:

Take a little time to read through the docs and refer to them when you get stuck, it helped me out.

1 Like

THANK YOU! The doc is a lifesaver.

Hello there,

Remember, Mongoose.js and MongoDB are quite different technologies. MongoDB is a database, and Mongoose.js is a JavaScript library which just so happens to wrap around a MongoDB database. So, you can just use MongoDB, and its provided API (for simple app structures/data I opt to do this), or you can use both MongoDB and Mongoose.js, in which case you interact with the Mongoose API, which interacts with the MongoDB API behind the scenes.

Yes, there are built-in methods, specific to subdocs. However, it is important to remember that the reason Mongoose.js is there is to wrap MongoDB (in this case), to provide you with a pretty doc structure. At the end of the day, everything is compiled (transpiled?) down to a MongoDB document.

MongoDB does not have a subdocument API, because everything within a MongoDB doc is (provided you are using the Nodejs API) a JS object. So, at the end of the day, JS objects are the expected, general way to interact with the doc structure.

Yes, but if you still get stuck, you can have a look at how the tests test: freeCodeCamp/issue-tracker.md at master · freeCodeCamp/freeCodeCamp (github.com)

Hope this helps

1 Like

Hi @Sky020,

Thanks for the comments.

I started looking into it and just got more confused.

Here’s my code for POST:

.post(function (req, res){
      let project = req.params.project; //this is important
      const issueTitle = req.body.issue_title;
      const issueText = req.body.issue_text;
      const createdBy = req.body.created_by;
      const assignedTo = req.body.assigned_to;
      const statusText = req.body.status_text;

      if(typeof(issueTitle) != 'string' || typeof(issueText) != 'string' || typeof(createdBy) != 'string'){
        res.send({error: 'required field(s) missing'});
      } else {
        const newIssue = {
          issue_title: issueTitle,
          issue_text: issueText,
          created_on: new Date().toISOString(),
          updated_on: new Date().toISOString(),
          created_by: createdBy,
          assigned_to: assignedTo,
          status_text: statusText,
        };

        Issue.find({project:project}, function(err, data){
          if (err) return (err);
          if (Object.keys(data).length===0){
            const initializer = new model({
              project: project,
              caselog: newIssue
            });
            //initializer is document of model Issue
            initializer.save(function(err, data){
              if (err) return (err);
              return res.json(data.caselog[0]);
            })
          } else {

            //this is the problem here
            let newList = data[0].caselog.unshift(newIssue);
            console.log(typeof(newList));
            //change so that you are unshifting within a save function
            
            Issue.findOneAndUpdate({project:project}, {caselog:newList}, {new:true}, function(err, data){
              if(err) return (err);
              console.log(data);
              console.log(newIssue);
              res.json(newIssue);

            })

for some reason, let newList = data[0].caselog.unshift(newIssue) is the number 2.

Here’s my code for PUT:

.put(function (req, res){
      let project = req.params.project;
      const issueId = req.body._id;
      const updatedOn = {updated_on: new Date().toISOString()};
      const updatedOnTarget = new Date().toISOString();

      const updatedIssue = {
        issue_title: req.body.issue_title,
        issue_text: req.body.issue_text,
        created_by: req.body.created_by,
        assigned_to: req.body.assigned_to,
        status_text: req.body.status_text,
        open: req.body.open ? 'false': '',
      }

      //only filter items that are not empty boxes
      let filteredItems = Object.entries(updatedIssue)
                                  .filter(element=> element[1] != '' && typeof(element[1]) === 'string')
                                  .reduce((accum, [key, value]) => {
                                    accum[key] = value; 
                                    return accum;
                                  }, {}); //this is the initial value, empty object

      if(typeof(issueId) != 'string'){
        //there is no id input by user
        return res.send({error: 'missing _id'});

      } 
      if (Object.keys(filteredItems).length === 0){
        return res.send({error: 'no update field(s) sent', _id: issueId});
      }
      filteredItems.updated_on = updatedOnTarget;

      //there is finding the item and then updating that item
      //returning a new caselog including the updated item

      let newList; 

        Issue.find({project:project}, function(err,data){
        if (err) return (err);
        const elementToUpdate = data[0].caselog.id(issueId);

        if(elementToUpdate === null){ //element does not exist
          return res.send({error: 'could not update', _id: issueId});
        } else { //element does exist
          const finalItems = Object.assign(filteredItems, updatedOn);  
          elementToUpdate.set(finalItems);

          newList = data[0].caselog;
          Issue.findOneAndUpdate({project: project}, {caselog: newList},  {new:true}, function(err, result){
            if (err) return (err);
            console.log(result);
            res.json({result: 'successfully updated', _id:issueId});
          })

          
        }
      })
    })

I’ve been working on it this whole week, and I feel like I’m getting nowhere. I think what’s tripping me is that I’ve been using Mongoose, and it’s not great at updating and editing subdocs.

I’m about to give up on this for a while now. I hope someone can help :frowning:

Guys, I think I solved it. In order to pass the tests (with Mongoose), each project is a separate MODEL. When I first started it, I had placed all the projects under one model, and the issues are caselogs in an array for each project object. This does not pass the FCC tests or the functional tests. Hope this helps others struggling.

Getting the Schema/Model/Document relationships are key here.

Also, getting enough rest and stepping away from FCC for a while, and then coming back :smiley: