Express controller doesn't get data after moongose 6 update (mdn local-library express tutorial)

Viewed 40

EDIT: the original title was "Updating to mongoose 6 an express project (mdn local-library express tutorial)" I changed it because I feel it is more precise this way.

I’m learning Express and I’m trying to replicate MDN local library shown in this tutorial.

I was able to make everything and customise it. However there is a bug in a controller (for book copies).

I can:

  • show the list of book copies (MDN calls them book instances),
  • display one book copy,
  • create a new one,
  • delete it from the database (mongo),
  • but not update it (which I was able to implement with books and authors).

So far I have:

  • tested the route, and it works correctly
  • reworked my code to match the original so I could copy and paste MDN original code (shown below), yet it didn’t work
  • changed books(callback) { Book.find(callback) } to books(callback) { Book.find({}, 'title').exec(callback) } and similar variations
  • tested the mongo query outside of this project to check if there were errors, it worked
  • checked the moongose debug (mongoose.set('debug', true)) , when I click the “update” link to open the form view, nothing appears in the console

I think the issue lays in the connection to mongo, the books collection specifically, and that the original code doesn’t work for me because my project has a more recent mongoose version. Similarly, I had to add the body-parser while the original doesn’t have it.

I’m trying to verify this hypothesis with the mongoose documentation and the migrating to 6 article. However, I’m a newbie and I’m afraid I bit more than I can chew, any advice is welcome.

My dependencies

"dependencies": {
    "async": "^3.2.4",
    "body-parser": "^1.20.0",
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "dotenv": "^16.0.1",
    "express": "~4.16.1",
    "express-validator": "^6.14.2",
    "http-errors": "~1.6.3",
    "luxon": "^3.0.1",
    "mongoose": "^6.5.0",
    "morgan": "~1.9.1",
    "pug": "^3.0.2"
  },

MDN project dependencies

 "dependencies": {
    "async": "^3.2.0",
    "compression": "^1.7.4",
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "express-validator": "^6.6.1",
    "helmet": "^4.1.1",
    "http-errors": "~1.6.3",
    "luxon": "^1.25.0",
    "mongoose": "^5.10.7",
    "morgan": "~1.9.1",
    "pug": "2.0.0-beta11"
  },

This is the piece of code where the bug occurs (I’m always redirected to the error page)

exports.bookinstance_update_get = (req, res, next) => {
  async.parallel(
    {
      bookinstance(callback) {
        BookInstance
          .findById(req.params.id)
          .populate('book')
          .exec(callback)
      },
      books(callback) { Book.find(callback) },
    },
    (err, results) => {
      if (err) return next(err)
      if (results.bookinstance == null) {
        let err = new Error('Book copy not found')
        err.status = 404
        return next(err)
      }
      res.render('bookinstance_form', {
        title: 'Update book copy',
        book_list: results.books,
        selected_book: results.bookinstance.book._id,
        bookinstance: results.bookinstance,
      })
    }
  )
}

This is a similar call that works correctly (to update books)

exports.book_update_get = (req, res, next) => {
  async.parallel(
    {
      book(callback) {
        Book.findById(req.params.id)
          .populate('author')
          .populate('genre')
          .exec(callback)
      },
      authors(callback) {Author.find(callback)},
      genres(callback) {Genre.find(callback)}
    },
    (err, results) => {
      if (err) return next(err)
      if (results.book == null) {
        const err = new Error('Book not found')
        err.status = 404
        return next(err)
      }
      for (const genre of results.genres) {
        for (const bookGenre of results.book.genre) {
          if (genre._id.toString() === bookGenre.id.toString()) genre.checked = 'true'
        }
      }
      res.render('book_form', {
        title: 'Update Book',
        authors: results.authors,
        genres: results.genres,
        book: results.book
      })
    }
  )
}

This is MDN original code, here is their local-library github repository

// Display BookInstance update form on GET.
exports.bookinstance_update_get = function (req, res, next) {
  // Get book, authors and genres for form.
  async.parallel(
    {
      bookinstance: function (callback) {
        BookInstance.findById(req.params.id).populate("book").exec(callback);
      },
      books: function (callback) {
        Book.find(callback);
      },
    },
    function (err, results) {
      if (err) {
        return next(err);
      }
      if (results.bookinstance == null) {
        // No results.
        var err = new Error("Book copy not found");
        err.status = 404;
        return next(err);
      }
      // Success.
      res.render("bookinstance_form", {
        title: "Update  BookInstance",
        book_list: results.books,
        selected_book: results.bookinstance.book._id,
        bookinstance: results.bookinstance,
      });
    }
  );
};
1 Answers

Ironically, after a whole week of tests I found a solution just after posting this question. It's not the prettiest, but it works and that's a big improvement.

Here is the working code:

exports.bookinstance_update_get = (req, res, next) => {
  BookInstance
    .findById(req.params.id)
    .populate('book')
    .exec((err, bookinstance) => {
      if (err) return next(err)
      if (bookinstance == null) {
        let err = new Error('Book copy not found')
        err.status = 404
        return next(err)
      }
      Book.find({}, 'title')
        .exec((err, books) => {
          if (err) return next(err)
          res.render('bookinstance_form', {
            title: 'Update book copy',
            book_list: books,
            selected_book: bookinstance.book._id,
            bookinstance: bookinstance,
          })
        })
    })
}
Related